在 C++ 中,在使用 多继承 时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。
如果发生了菱形继承,这个时候类 A 中的 成员变量 和 成员函数 继承到类 D 中变成了两份,一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。如下图所示:
在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。
假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B–>D 这条路径,还是来自 A–>C–>D 这条路径。
菱形继承会存在命名冲突
#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;
}
程序运行后,控制台输出如下:
我们首先定义了基类 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;
}
程序运行后,控制台输出如下:
这次,我们在子类 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;
}
程序运行后,控制台输出如下:
这次,我们在子类 D 中,指明了访问的成员 m_a 是来自类 B 的,因此,程序不再报错。
在 C++ 中,在使用多继承时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。
如果发生了菱形继承,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。