views:

287

answers:

8

This is one of the boring academic OOP questions, but it is not a homework. I got the question from a newbie programmer about one of those stupid textbooks examples about OOP.

Imagine that you are designing a Square class and a Cube class, which should inherit which?

I see a relationship, but what it is, I can not really see!

Could you give me a logical argument with OOP in mind.

+22  A: 

Neither! Since a square is not a cube, and a cube is not a square, neither should inherit from the other. Square can inherit from polygon and cube can inherit from polyhedron, but the two are, themselves, mutually exclusive.

Bob Kaufman
+1 for better inheritance model
RedFilter
I agree: neither. I could see a has-a relationship, however: a Cube has a collection of 6 Squares.
Nelson
It does make sense to me :) Thanks.
AraK
You could also mention composition. A Cube can be *composed* of six Squares constrained in a specific relationship.
Mark Canlas
+14  A: 

There's no inheritance. Inheritance is a "is-a" relationship (Well, sometimes not even a "is-a" relationship, as mentioned in the link below). A cube is not a square, and a square is not a cube.

How would you construct, it depends on how you model. You could go with something like a cube has 6 squares (a cube is not, it has 6 squares; a composition), or a cube has a side size, just like square. But once there is no "is-a", an inheritance would be dangerous zone...

Also, in a inheritance, everything that is valid for the base class must be valid for the Derived one. It's the Square extends Rectangle problem. For instance:

Supposing Cube inherits Square: If your Square has a method changeArea(double area) and getSide(), the same should be possible for the Cube. But it is not, since the area of a cube is 6 times the area of a square (it has 6 squares).

Supposing Square inherits Cube: If your Cube has a setVolume(double volume) method, your square will be broken, once it has no volume

Finally, if you want to use inheritance, you could create a GeometryObjectWithEqualSides object, then both could inherit from it. :)

Samuel Carrijo
A cube IS A square but with a third dimension (depth)
TheTXI
+1 for providing a clear rule of thumb
RedFilter
But in this case I would agree with you...there isn't much you would inherit from a square that wouldn't needed to be overloaded
TheTXI
And a dog is a man with 2 extra legs. :)
RedFilter
A cube has 6 square shaped faces but is not a square, there really is no is-a relationship between the two
SpaceghostAli
Hmm. That brings another question up. Implement IEquilateral and inherit from Polygon or ThreeDimensional, or implement IPolygon or IThreeDimensional and inherit from Equilateral?I was leaning towards the first, but the second makes more sense now; at least Equilateral can set a SideSize property while all you'd be doing with Polygon and ThreeDimensional is overriding Area() and Volume()...
aehiilrs
A: 

Neither should inherit the other. One is a 2-dimensional shape, the other is a 3-dimensional object. There really isn't enough similarity between the two to justify inheritance.

Now you might conceivably make a cube composed of squares, if you need a separate object for each side ;)

Sean Nyman
+5  A: 

Having it either way would be a violation of the Liskov Substitution Principle.

JP Alioto
+1  A: 

Both inherit from hypercube

ymv
No. A square isn't a cube, a cube isn't a hypercube, a square isn't a hypercube.
Svante
Actually, they are. A hyper cube is another name for what might be called an N-cube. a square is a 2-cube, a cube is a 3-cube, etc.
Mike Cooper
+1  A: 
struct Square // Rectangle actually
{
  Square( int dx, int dy ) : dx(dx), dy(dy) {};

  int dx;
  int dy;

  int floor_area() { return dx*dy; };
};

struct Cube : Square  // Cuboid actually
{
  Cube( int dx, int dy, int dz ) : Square(dx, dy), dz(dz) {};

  int dz;

  int cube_area() { return floor_area()*2+dx*dz*2+dy*dz*2; };
};

Seems to be that Liskov substitution principle is not violated here.

Kirill V. Lyadvinsky
Hmmm...! Although I disagree with the logic your answer implies, every example that comes to mind actually supports your answer. Grrr!
Bob Kaufman
This is erroneous. What is the implementation of the area() method? Would it be the area of all sides or that of the base? I have a room that I want to floor. I go to the shop and ask for squares that I can use (different materials) but the tender gives me concrete cubes...
David Rodríguez - dribeas
Getting closer to code, Cube has a Square (the base) and a height, but it is not a Square. You cannot use Cube's where Squares are required (if a pyramid has a squared base, you cannot use a Cube there).
David Rodríguez - dribeas
I'll be able to use Cube in pyramid with z=0.
Kirill V. Lyadvinsky
A: 

Most of comments here are correctly saying that none of them should inherit from another. This is true in most cases. But I think there is more generic answer: It depends on your expectations on them. You expect Square to do what? Does Cube also do it? May be the other way - can you use Square whenever you use Cube? I think both statements "Cube does all what Square does" and "Square does all what Cube does" are false, according to common sense, so none of them should inherit from another. However, it is up to you to decide their structure and behavior, because it is you who defines what your program does and what it consists of.

Most likely "Cube contains 6 Squares" is the relationship that you saw.

Pavel Feldman
+1  A: 

The square and the cube could be argued to be two instances of the same class "Hypercube" which would also encompass the point (0 dimensions), the line segment (1 dimension) and others beyond that. The number of dimensions and the length of one side are enough to define a specific instance of Hypercube (you could of course add an n-dimensional point of origin and orientation).

The hypercube could provide functions/methods that return values for the number of vertices, edges, faces, etc. for that particular instance.

See Hypercube on Wikipedia for more info.

Galghamon