开发者

Virtual keyword makes inaccessible a method from the derived objects

开发者 https://www.devze.com 2023-04-12 08:36 出处:网络
I have this code: #include <iostream> class Super{ public: virtual void showName(); }; class Special1 : public Super {

I have this code:

#include <iostream>

class Super{
public:
    virtual void showName();
};

class Special1 : public Super {
public:
    void showName();
    void sayHello();
};

class Special2 : public Super {
public:
    void showName();
    void sayGoodbye();
};

void Super::showName() {
    std::cout << "I'm super!" << std::endl;
}

void Special1::showName() {
    std::cout << "I'm special1" << std::endl;
}

void Special1::sayHello() {
    std::cout << "Hello" << std::endl;
}

void Special2::showName() {
    std::cout << "I'm special2" << std::endl;
}

void Special2::sayGoodbye() {
    std::cout << "Goodbye" << std::endl;
}

int main () {
    Super *oSpec=new Super;

    Special1 *o1=st开发者_运维百科atic_cast<Special1 *>(oSpec);
    Special2 *o2=static_cast<Special2 *>(oSpec);

    oSpec->showName();
    o1->showName();
    o2->showName();

    o1->sayHello();
    o2->sayGoodbye();

    delete oSpec;

    return 0;
}

When I run it, it shows this output:

I'm super!
I'm super!
I'm super!
Hello
Goodbye

But, if I remove the virtual keyword from the declaration of the Super class:

class Super{
public:
    /*virtual*/ void showName();
};

The output becomes the correct one:

I'm super!
I'm special1
I'm special2
Hello
Goodbye

Then, my question is, why the presence of the virtual keyword makes the pointers o1 and o2 run the method Super::showName() instead of Special1::showName() or Special2::showName()?


The output is closer to correct with virtual and incorrect with it (unless you really wanted that). The cast doesn't change the type of the objects, just the type of the pointers. They are still of type Super, and so it's Super::showName that should run.

Casting one pointer type to another pointer type doesn't change the type of the thing pointed to. How could it? The whole point of virtual functions is to be able to call methods on 'generic' pointers and get the correct derived class method.

The classic example of why you use virtual functions is for musicians. You might have a function that causes the entire orchestra to play by calling the Play method on every Musician * it gets passed. For a Pianist, that has to call Pianist::Play.

Normally, the compiler figures out which function to call at compile time -- early binding. The only information the compiler is sure to know is the type of the pointer. The virtual keyword causes the binding to occur late, at run time, when the actual type of the class member is known.

By the way, you can still call the base class method, by using a scope override. For example o1->Super::showName();.

In fact, the result you claim is 'correct' is catastrophic. Running Special1::showName() with the this pointer pointing to an object that is not of type Special1 (or something derived from it) is undefined behavior and can easily lead to a crash.


Because your code in main is wrong. The objects all say "I'm super" because for them (in reality, in the background), the most derived type is still super. That's what they were created as.

Your static cast breaks all the rules, to be undefined behavior (anything can happen), because you tell the compiler that o1 is a Special1, when in fact, it is not a type of Special1.

virtual functions are usually useful when you create a bunch of derived objects, and store them in a pointer/container that holds pointers to the base object. Not the other way around. You want to create pointers of type Special1 and Special2 and store them in pointers to super.


Your cast (Special1 *o1=static_cast<Special1 *>(oSpec);) is undefined behavior in both cases, so any output at all is acceptable as far as the language is concerned. You've taken an object of type Super and lied to the compiler, telling it that it's really a derived class. In this case, what happens is that you still get the result of the parent class Super that it really is.


Your code is just undefined.
Trying to reason why it works in a particular way is useless.

Here:

Super *oSpec=new Super;

oSpec points at an object of type Super.

Thus in these statements. The casts have undefined behavior, as the object pointed at by oSpec is neither a Special 1 or a Special 2).

Special1 *o1=static_cast<Special1 *>(oSpec);
Special2 *o2=static_cast<Special2 *>(oSpec);

If you use dynamica_cast<> (like you should when casting up the class hierarchy). You will find the result are NULL.

Special1 *o1=dynamic_cast<Special1 *>(oSpec);
Special2 *o2=dynamic_cast<Special2 *>(oSpec);

std::cout << "O1(" << (void*)o1 << ") O2(" << (void*)o2 << ")\n";

This will show that both pointers are NULL.

0

精彩评论

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