简体   繁体   中英

mixture of virtual and non-virtual inheritance

while trying to analyse in greater depth inheritance mechanism of C++ I stumbled upon the following example:

#include<iostream>

using namespace std;

class Base {
public:
    virtual void f(){
    cout << "Base.f" << endl; 
    }
};

class Left : public Base { //NOT VIRTUAL!!!
public:
void g(){ 
        f();
    }     
};

class Right : public Base{
public:
    virtual void f(){
    cout << "Right.f" << endl; 
    }
};

class Bottom : public Left, public Right{
public:
    Bottom(int arg){ }
    //void f() { }
};

int main(int argc,char **argv)
{
    Bottom* b = new Bottom(23);
    b->g();
}

It is clear that calling

b->f()

is ambiguous, so there is no unique method f() on object Bottom. Now, calling

b->g()

works fine and prints

Base.f

Well, as far as I see this:

  1. static type is Bottom, so we call its g() method, as it is non-virtual
  2. g() method is inherited from Left, so we call this inherited method
  3. Now, g() in Left tries to call virtual method f() . According to C++ sepcification, we call f() method of a dynamic type of our pointer (which is Bottom)

BUT Bottom does not have method f() ... at least not a unique one. Why does this program executes Left::Base::f() rather than Right::Base::f() or why does it simply not states that call to f() is ambiguous from Bottom?

The short answer is that (as you noted), Bottom does not have method f() , so there is no need in trying to call it.

Bottom contains the two subobjects Left and Right . Each of them inherits from Base , so Bottom contains the member functions Left::f() and Right::f() , but no Bottom::f() . Since Bottom does not override Left::f() (using Right::f() for example), Base::f() is the unique final overrider in Left::g() .

cf. the example in 10.3.9 from the C++03 standard.

Since there is no virtual inheritance there are two copies of the Base object in your Bottom object. But if you move up the hierarchy to Left where g() is defined, there is a single Base subobject and that is the one being called. Since it is not overridden in Left (or Bottom ) it will call the Base version. Note that Right::f() only overrides f() for it's own Base subobject.

Calling f directly on Bottom is ambiguous, as there is no f() in Bottom it will try to look in it's bases and will find Left::Base::f and Right::Base::f and the compiler does not know which of the two to use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM