项目中有类似于这样结构的一段代码,特此记录一下调试结果。
class A
{
public:
virtual void func() = 0;
};
class B :public A
{
int b = 1;
public:
virtual void func() override
{
}
};
class C :public A
{
public:
virtual void g()
{
}
private:
int c = 3;
};
class D : public B, public C
{
int d = 4;
public:
virtual void g() override
{
}
virtual void func() override
{
B::func();
}
};
int main(){
B* p = new D;
可以在调试窗口看到监视信息:
这里因为是菱形继承,所以而且A是抽象类,因为 D 从 C 分支也继承自A, 所以在D内部,必须也给出 func 的定义,否则D 也是抽象类,则不能实例化,发生编译错误。
VS 的监视窗口给出的信息,p 的静态类型是B* , p 自身拥有的而非通过继承而来的成员 b 在最下方。p 指向的对象的动态类型是 D。由于是菱形继承,造成了 A 的子对象实际会出现两次,所以看到中间有个额外的 A 对象。
2、更改为虚继承。
class A
{
public:
virtual void func() = 0;
};
class B : virtual public A
{
int b = 1;
public:
virtual void func() override
{
}
};
class C : virtual public A
{
public:
virtual void g()
{
}
private:
int c = 3;
};
class D : public B, public C
{
int d = 4;
public:
virtual void g() override
{
}
};
int main(){
B* p = new D();
B* p2 = new B();
改成虚继承, D 中不必再去实现 func 。比较有意思的是可以看到监视窗口中给出,p 和 p2 的结果相同,都是指向的 B 类型对象。这是应为虚继承时,虚基类在每个派生类中都是独立的,上边 B,C,D 对象中包含的 A 对象都是独立的(D中的A 对象并不属于B或者C子对象当中),也就是说,D 中的 func 并不是从 B 中继承而来,而是直接从 A 中继承而来。
换句话说,基类指针或者引用指向派生类对象,实际上指向的是派生类中的基类子对象(派生类对象中包含完整的基类对象)。C++ 中的多态又是通过虚函数表来实现,而 B 的虚函数表是 A 而来的,即 p 指向的子对象中没有与 D 相关的虚函数信息(多态信息)。
。这样导致 D 并没有从 B 继承来与动态类型相关的东西(虚函数),所以看到 p 和 p2 的结果相同。
3、加入在 B 中加入虚函数,
class A
{
public:
virtual void func() = 0;
};
class B : virtual public A
{
public:
virtual void func() override
{
}
virtual void test_func()
{
}
private:
int b = 1;
};
class C : virtual public A
{
public:
virtual void g()
{
}
private:
int c = 3;
};
class D : public B, public C
{
int d = 4;
public:
virtual void g() override
{
}
virtual void func() override
{
}
void sayHello()
{
std::cout << "hello" << "\n";
}
};
int main(){
B* p = new D();
B* p2 = new B();
可以看到这个时候,监视窗口显示的 p 实际的指向的类型已经变成 D (即*p 的动态类型)。