开发者

Some final questions about inheritance/casting

开发者 https://www.devze.com 2023-01-08 04:13 出处:网络
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.

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?

  1. Why is the compiler not complaining for using members of the base class when I am using a derived pointer?

  2. 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){}
0

精彩评论

暂无评论...
验证码 换一张
取 消