What rule am I breaking to get "invalid conversion from 'Der**' to 'Base**' [-fpermissive]"?
A pointer to a derived class is type-compatible with a pointer to its base class.
So I don't think I am breaking a polymorphism rule.
#include <iostream>
class Base
{
public:
void print() { std::cout << " Base"; }
};
class Der: public Base
{
public:
void print() { std::cout << " Der"; }
};
class Container
{
private:
Base** ptrsBase; //array of Base pointers
public:
//Base* parameter does not accept Der* even though it is a kind of Base*
Container(Base* pb[]): ptrsBase(pb) {}
};
int main()
{
Base b;
Der d;
//Base* ptrsArray[] = { &b, &d }; //polymorph works when array type is Base*
Der* ptrsArray[] = { &d, &d }; //compile fails when array type is Der*
Container containter(ptrsArray); //error: invalid conversion from 'Der**' to 'Base**' [-fpermissive]
b.print();
d.print();
}
compile error messages:
C:\Users\wolf\Documents\>g++ polymorph_pointer.cpp
polymorph_pointer.cpp: In function 'int main()':
polymorph_pointer.cpp:31:32: error: invalid conversion from 'Der**' to 'Base**'[-fpermissive]
Container containter(ptrsArray);
^
polymorph_pointer.cpp:21:3: error: initializing argument 1 of 'Container::Container(Base**)' [-fpermissive]
Container(Base* pb[]): ptrsBase(pb) {}
^
//Base* parameter does not accept Der* even though it is a kind of Base*
Wrong. Der is a kind of Base, therefore pointers to Der are convertible to Base. Der* is not a kind of Base* so it is impossible to freely convert those.
It is not only syntax pedancy, it is also saves you from errors like:
1 2 3 4 5 6 7 8 9
struct B {};
struct D1 : B {};
struct D2 : B {};
D1** foo;
//Fill foo
B** bar = (B**)foo; //Bad
bar[0] = new D2; //Now first element of foo array points to D2
foo[0].do_something();//Warning, called on actually D2 object. D1 and D2 are not compatible at all!!
MiiNiPaa,
Thank you for the counter example. It made me understand.
Here is my interpretation of your example:
1 2 3 4 5 6 7 8 9 10 11
struct B {}; //B is a base class
struct D1 : B {}; //D1 is a kind of B
struct D2 : B {}; //D2 is a kind of B
D1** foo; //foo is an array of D1 pointers
B** bar; //bar is an array of B pointers
bar = foo; //bar array is foo array (this should no compile)
D2 d2; //d2 is a D2 object
bar[0] = &d2; //first element of foo array points to a D2 object
//foo was supposed to be an array of just D1 pointers
//this is why the compiler insists that pointer types match
All Der instances are also Base instances, so it's safe to case from a Der* to a Base*. But not all Base instances are Der instances, so you can't cast the other way. To see this, add some data to the classes and force bArray to work:
Here dArray[0].dval is garbage because dArray[0] points to b, which is a Base and doesn't even have a dval member.
The bottom line is that you can cast a pointer or reference to a derived class into a pointer/reference to the Base class because there is always a Base instance there. But the reverse isn't always true.