Some final questions about inheritance/casting
I asked a question an hour or two ago that is similar but this is fundamentally different to me. After this I should be good.
class base
{
private:
string tame;
public:
void kaz(){}
virtual ~base() {}
void print() const
{
cout << tame << endl;
}
};
class derived: public base
{
private:
string taok;
public:
std::string name_;
explicit derived( const std::string& n ) : name_( n ) {}
derived(){}
void blah(){taok = "ok";}
void print() const
{
std::cout << "derived: " << name_ << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
base b;
derived d;
base * c = &b;
开发者_C百科 derived * e = (derived *)&b;
e->kaz();
system("pause");
return 0;
}
I know downcasting in in this example is not good practice but I'm just using it as an example. So when I now am pointing to a base object from a derived pointer, I don't get why I am still able to do certain operations only belonging to the base class.
For example, the base class's interface has a Kaz() method but the derived method does not. When I downcast, why does the compiler not yell at me for doing this even though Kaz() is not part of the derived class's interface?
Why is the compiler not complaining for using members of the base class when I am using a derived pointer?
Why does the compiler yell at me only when I access a member from the base class interface from within a method but not directly?
For example:
I can't do this:
e->print() //Program crashes
But I can do this:
e->tame = "Blah";
cout << e->tame << endl;
First you should use dynamic_cast<derived*>(&b)
instead of the C-style cast.
Then you should declare the print()
method as virtual
if you want to override the method in the subclass.
The line e->tame = "Blah";
should cause the compiler to issue an error if not used inside of a class method because it is declared private
.
Last the kaz()
method can be called on the derived object because the subclass contains all methods from the base class plus the ones defined in the derived class.
The derived class inherits all the members of the base class, so kaz()
exists also for derived
objects. If you call kaz()
on a derived
object, simply the method that was inherited from base
is called. If you access the inherited members from within a method or directly doesn't matter.
The problem with e
is that it is really pointing to a base
object, not a derived
. With the cast e = (derived *)&b
you tell the compiler "I know it doesn't look like it, but this really is a derived *
, believe me!". And the compiler believes you, since you are the master. But you lied and &b
was actually not a derived*
. Therefore horrible things happen when the compiler tries to call derived::print()
on it, in this case it leads to a crash of the program.
When you access e->tame
directly, also horrible things could happen (the compiler still treats e
as a derived*
while it only is a base*
). In this case, by chance, it happens to print out the expected value anyway.
From the compiler standpoint, e is a "derived" object pointer.
From the runtime standpoint, e is pointing to a "base" object, so e->name_ is pointing to a random address. Eventhough you cast it, it doesn't change the fact that it is a "base" object that was allocated.
If you take a closer look, none of the derived constructors initializes the base name, and neither does the base constructor (which is the only one used).
So when you do e->print()
the value you want to print is undefined.
When you manually set it, its no longer undefined. So a call to e->print()
will work just fine
You could try this
In base class define a non-default constructor that receives a name
base(std::string name):tame(name){}
精彩评论