If you want your Square be a Rectangle , it must publicly inherit it. However, this means that any public methods that work with Rectangle must be appropriately specialized for Square . In this context
 void makeBigger(Rectangle& r) 
It should not be a standalone function, but a virtual Rectangle member that is redefined in Square (by providing its own) or hidden (via using makeBigger in the private section).
Regarding the question that some of the things you can do with a Rectangle cannot be done with Square . This is a common design dilemma, and C ++ is not design. If someone has a link (or pointer) to a Rectangle , which is actually a Square , and you want to perform an operation that does not make sense for Square , then you should handle it. There are several options:
1 use public inheritance and throw a Square exception if the operation is running, which is impossible for Square
 struct Rectangle { double width,height; virtual void re_scale(double factor) { width*=factor; height*=factor; } virtual void change_width(double new_width)  
This is really inconvenient and not suitable if change_width() or change_height() are integral parts of the interface. In this case, consider the following.
2 you can have one class Rectangle (which may turn out to be square) and, optionally, a separate class Square that can be converted ( static_cast<Rectangle>(square) ) to Rectangle and therefore act like a rectangle, but you should not change how a Rectangle
 struct Rectangle { double width,height; bool is_square() const { return width==height; } Rectangle(double w, double h) : width(w), height(h) {} };  
This option is the right choice if you allow changes to the Rectangle that can turn it into Square . In other words, if your Square not a Rectangle , as it is implemented in your code (with independently adjustable width and height). However, since Square can be statically added to a Rectangle , any function that takes a Rectangle argument can also be called using Square .