虚拟和非虚拟继承的混合
mixture of virtual and non-virtual inheritance
在试图更深入地分析C++的继承机制时,我偶然发现了以下示例:
#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();
}
很明显,打电话
b->f()
是模棱两可的,因此在对象底部没有唯一的方法f()
。现在,打电话
b->g()
工作正常并打印
Base.f
好吧,据我所知:
- 静态类型是 Bottom,所以我们称它为
g()
方法,因为它是非虚拟的 -
g()
方法是从 Left 继承的,所以我们称之为继承的方法 - 现在,左边的
g()
尝试调用虚拟方法f()
。根据C++分离,我们调用f()
指针的动态类型的方法(即 Bottom)
但是底部没有方法f()
...至少不是独一无二的。为什么这个程序执行Left::Base::f()
而不是Right::Base::f()
,或者为什么它根本不声明对f()
的调用从底部是模棱两可的?
简短
的回答是(如您所指出的),Bottom
没有方法f()
,因此无需尝试调用它。
Bottom
包含两个子对象Left
和Right
。它们中的每一个都继承自Base
,所以Bottom
包含成员函数Left::f()
和Right::f()
,但没有Bottom::f()
。由于 Bottom 不会覆盖Left::f()
(例如使用 Right::f()
),因此 Base::f()
是 Left::g()
中唯一的最终覆盖器。
参见 C++03 标准 10.3.9 中的示例。
由于没有虚拟继承,因此Bottom
对象中有两个Base
对象的副本。但是,如果将层次结构向上移动到定义g()
Left
,则只有一个Base
子对象,这就是被调用的对象。由于它没有在Left
(或Bottom
)中被覆盖,它将调用Base
版本。请注意,Right::f()
仅覆盖其自己的Base
子对象的f()
。
直接在Bottom
上调用f
是模棱两可的,因为没有f()
Bottom
它会尝试查看其基础并会找到Left::Base::f
和Right::Base::f
,编译器不知道使用两者中的哪一个。
相关文章:
- 虚拟决赛作为安全
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- 如何在C++中获得"静态纯虚拟"功能?
- C++无法定义虚拟函数 OUTER 类和头文件
- 混合组合和继承的C++问题
- 在混合代码库中将C转换为C++时出现许多包含错误
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- D3D11-将混合权重和索引传递到顶点着色器
- 大小虚拟继承中的派生类
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 使用 C++ 和 i2c 工具从虚拟 i2c 写入和读取
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- 是否可以混合使用虚拟函数和函数对象以使用标准算法
- MinGW 4.7.0 到 4.7.2 错误:使用混合虚拟和非虚拟多重继承时成员函数中的"this"指针无效
- 虚拟和非虚拟继承的混合