Inheritance - why is it illegal?

I am passing a C ++ test. And I came across the following code - it is illegal, but I can not understand why. Can anyone explain why this line is:

Box* b1 = s1->duplicate(); 

generates a compiler error, "cannot convert from Shape * to Box"? I suggested that s1->duplicate() calls Box::duplicate() , because s1 actually points to Box , but from a compiler error, it looks like the caller is Shape::duplicate() .

 #include <iostream> struct Shape { virtual Shape* duplicate() { return new Shape; } virtual ~Shape() {} }; struct Box : public Shape { virtual Box* duplicate() { return new Box; } }; int main(int argc, char** argv) { Shape* s1 = new Box; Box* b1 = s1->duplicate(); delete s1; delete b1; return 0; } 
+8
c ++ inheritance types typechecking
source share
3 answers

Shape::duplicates() returns a Shape* , which is not Box* . The type of execution that you are actually returning has nothing to do with it. How could the compiler know that the returned Shape* points to Box ?

Edit: think about this:

 struct Shape { virtual Shape* duplicate() { return new Shape; } virtual ~Shape() {} }; struct Box : public Shape { virtual Box* duplicate() { return new Box; } }; struct Sphere : public Shape { virtual Sphere* duplicate() { return new Sphere; } }; Shape* giveMeABoxOrASpehere() { if ( rand() % 2 ) return new Box; else return new Sphere; } // Shape* shape = giveMeABoxOrASphere(); // What does shape->duplicate() return? Box* shape = giveMeABoxOrASphere(); // shoud this compile? 
+8
source share

C ++ is statically typed. Decisions about the legality of your call are made at compile time. Obviously, the compiler cannot know that s1->duplicate() returns a pointer to a Box object. Under these conditions, it would be illogical to expect it to accept your code.

Yes, s1->duplicate() does indeed call Box::duplicate in your example, but how do you expect the compiler to know about it? You can say that this is "obvious" from your specific example, but the specification of this language function does not make an exception for such "obvious" cases.

+15
source share

For the same reason

 Shape* s1 = new Box; Box* b1 = s1; 

not compiled. The compiler does not care that s1 refers to Box , and it does not have to worry.

If you know that s1 refers to Box , just say:

 Box *s1 = new Box; 

Syntax Note: Parsing Rules for Box * s1; (very simplified):

 declaration := type-name declarator ; declarator := name | * declarator 

therefore parsing:

  Box * s1 ; ^^^^^^^^ declarator ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ type-name declarator 

and Box (* (s1) ) grouping Box (* (s1) )

Considered the best writing style for Box *s1; because it is more consistent with parsing than Box* s1; If you declare more than one variable in a single declaration, the Box* syntax can be misleading:

 Box* x, y; 

x is a pointer to Box , but y is Box , because the parsing is:

 Box (*x), y; 
+1
source share

All Articles