C++菱形继承

C++菱形继承教程

C++ 中,在使用 多继承 时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。

如果发生了菱形继承,这个时候类 A 中的 成员变量成员函数 继承到类 D 中变成了两份,一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。如下图所示:

20_C菱形继承.png

在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。

假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B–>D 这条路径,还是来自 A–>C–>D 这条路径。

案例

C++菱形继承

菱形继承会存在命名冲突

#include <iostream> using namespace std; // 间接基类A class A { protected: int m_a; }; // 直接基类B class B: public A { protected: int m_b; }; // 直接基类C class C: public A { protected: int m_c; }; //派生类D class D: public B, public C { public: void setb(int b) { m_b = b; //正确 } void setc(int c) { m_c = c; //正确 } void setd(int d) { m_d = d; //正确 } private: int m_d; }; int main() { cout << "嗨客网(www.haicoder.net)\n" << endl; D d; return 0; }

程序运行后,控制台输出如下:

21_C菱形继承.png

我们首先定义了基类 A,接着定义了类 B 继承自类 A,类 C 也继承自类 A,最后,我们定义的类 D 继承了类 B 和类 C,此时就形成了菱形继承,运行程序,程序运行正常,现在我们修改程序如下:

#include <iostream> using namespace std; // 间接基类A class A { protected: int m_a; }; // 直接基类B class B: public A { protected: int m_b; }; // 直接基类C class C: public A { protected: int m_c; }; //派生类D class D: public B, public C { public: void seta(int a) { m_a = a; //命名冲突 } void setb(int b) { m_b = b; //正确 } void setc(int c) { m_c = c; //正确 } void setd(int d) { m_d = d; //正确 } private: int m_d; }; int main() { cout << "嗨客网(www.haicoder.net)\n" << endl; D d; return 0; }

程序运行后,控制台输出如下:

22_C菱形继承.png

这次,我们在子类 D 中,直接访问了从类 A 中继承来的成员变量 m_a,此时程序报错,因为,这时候的菱形继承,此时,类 D 中有两份成员变量 m_a,一份是来自从 A->B->D 的路径,一份是来自从 A->C->D 的路径。

因此,此时程序报错,现在,我们修改程序,指明我们需要具体访问的成员 m_a,代码如下:

#include <iostream> using namespace std; // 间接基类A class A { protected: int m_a; }; // 直接基类B class B: public A { protected: int m_b; }; // 直接基类C class C: public A { protected: int m_c; }; //派生类D class D: public B, public C { public: void seta(int a) { B::m_a = a; //命名冲突 } void setb(int b) { m_b = b; //正确 } void setc(int c) { m_c = c; //正确 } void setd(int d) { m_d = d; //正确 } private: int m_d; }; int main() { cout << "嗨客网(www.haicoder.net)\n" << endl; D d; return 0; }

程序运行后,控制台输出如下:

23_C菱形继承.png

这次,我们在子类 D 中,指明了访问的成员 m_a 是来自类 B 的,因此,程序不再报错。

C++菱形继承总结

在 C++ 中,在使用多继承时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。

如果发生了菱形继承,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。