[C++] 菱形继承

这里,我们要讨论下虚基类成员的可见性

理论基础

假定类B定义了一个名为x的成员,D1和D2都是从B 虚继承 得到的,D继承了D1和D2,则通过D的对象使用x,有三种可能性:

  • 如果在D1和D2中都没有x的定义,则x将被解析为B的成员,此时不存在二义性,一个D的对象只含有x的一个实例;
  • 如果D1或D2中某一个成员定义了x,则同样没有二义性,派生类的x比虚基类中的x优先级更高
  • 如果D1和D2都定义了x,存在二义性;

具体例子

该例子是C++ Primer 18.24题,在这里我简单地做了些修改。
原题中D1::bar(char)以及D1::foo(char)存在char<->int间隐式类型转换的问题,
为了更加直观,我改成了string。


struct Base {
    void bar(int i);

protected:
    int ival;
};

struct D1 : virtual public Base {
public:
    void bar(string i); // orig: char i
    void foo(string i); // orig: char i

private:
    char cval;
};

struct D2 : virtual public Base {
public:
    void foo(int i);

protected:
    int ival;
    char cval;
};

class VMI : public D1, public D2 {};

题目中问在VMI类内部有哪些继承而来的成员可以无需限定符即可访问?

按照上述的规则,我们可以知道只有D1::foo()以及D2::ival。

深层次原理

  • 派生类的作用域嵌套在直接基类的作用域中。
  • 名字查找过程沿着集成体系自底向上进行,直到找到所需的名字。
  • 在多重继承时,相同的查找过程在所有直接基类中同时进行。

实验代码

#include <iostream>

using namespace std;

struct Base {
    void bar(int i) { cout << __FUNCTION__ << i << endl; }

protected:
    int ival = 0;
};

struct D1 : virtual public Base {
public:
    void bar(char i) { cout << __FUNCTION__ <<  i << endl; }
    void foo(char i) { cout << __FUNCTION__ <<  i << endl; }

private:
    char cval = 'a';
};

struct D2 : virtual public Base {
public:
    void foo(int i) { cout << __FUNCTION__ << i <<endl; }

protected:
    int ival = 1;
    char cval = 'b';
};

class VMI : public D1, public D2 {
public:
    void verify() {
        cout << ival << endl;
        bar('x');
        bar(42);
    }
};

int main()
{
    VMI vmi;

    vmi.verify();
}

猜你喜欢

转载自blog.csdn.net/sai_j/article/details/79529907
今日推荐