Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
虚拟多重继承-最终重写器 在试图更深入地分析C++的继承机制时,我偶然发现了以下的例子: #include<iostream> using namespace std; class Base { public: virtual void f(){ cout << "Base.f" << endl; } }; class Left : public virtual Base { }; class Right : public virtual Base{ public: virtual void f(){ cout << "Right.f" << endl; } }; class Bottom : public Left, public Right{ }; int main(int argc,char **argv) { Bottom* b = new Bottom(); b->f(); } #包括 使用名称空间std; 阶级基础{ 公众: 虚空f(){ cout_C++_Multiple Inheritance_Virtual Inheritance - Fatal编程技术网

虚拟多重继承-最终重写器 在试图更深入地分析C++的继承机制时,我偶然发现了以下的例子: #include<iostream> using namespace std; class Base { public: virtual void f(){ cout << "Base.f" << endl; } }; class Left : public virtual Base { }; class Right : public virtual Base{ public: virtual void f(){ cout << "Right.f" << endl; } }; class Bottom : public Left, public Right{ }; int main(int argc,char **argv) { Bottom* b = new Bottom(); b->f(); } #包括 使用名称空间std; 阶级基础{ 公众: 虚空f(){ cout

虚拟多重继承-最终重写器 在试图更深入地分析C++的继承机制时,我偶然发现了以下的例子: #include<iostream> using namespace std; class Base { public: virtual void f(){ cout << "Base.f" << endl; } }; class Left : public virtual Base { }; class Right : public virtual Base{ public: virtual void f(){ cout << "Right.f" << endl; } }; class Bottom : public Left, public Right{ }; int main(int argc,char **argv) { Bottom* b = new Bottom(); b->f(); } #包括 使用名称空间std; 阶级基础{ 公众: 虚空f(){ cout,c++,multiple-inheritance,virtual-inheritance,C++,Multiple Inheritance,Virtual Inheritance,在可怕的钻石中有一个单一的基,两个中间对象从中派生,然后第四个类型通过中间级别中两个类型的多重继承关闭钻石 您的问题似乎是在前面的示例中声明了多少个f函数?答案是一个 让我们从一个简单的例子开始,这个简单的例子是一个线性层次结构,它只包含基和派生: struct base { virtual void f() {} }; struct derived : base { virtual void f() {} }; 在此示例中,声明了一个f,其中有两个重写,base::f和deriv

在可怕的钻石中有一个单一的基,两个中间对象从中派生,然后第四个类型通过中间级别中两个类型的多重继承关闭钻石

您的问题似乎是在前面的示例中声明了多少个
f
函数?答案是一个

让我们从一个简单的例子开始,这个简单的例子是一个线性层次结构,它只包含基和派生:

struct base {
   virtual void f() {}
};
struct derived : base {
   virtual void f() {}
};
在此示例中,声明了一个
f
,其中有两个重写,
base::f
derived::f
。在类型为
derived
的对象中,最后一个重写器是
derived::f
。需要注意的是,两个
f
函数都表示一个具有多个实现的函数赞美诗

现在,回到原始示例,在右侧的行上,
Base::f
right::f
以相同的方式被重写。因此对于
right
类型的对象,最终重写器是
right::f
。现在对于
Left
类型的最终对象,最终重写器是
Base::f
as
Left
不会覆盖该功能

当菱形关闭时,由于继承是
虚拟的
,因此有一个
Base
对象,它声明一个
f
函数。在继承的第二级中,
Right
用它自己的实现重写该函数,这是最派生的
底部类型的最终重写器

您可能希望在标准之外了解这一点,并了解编译器如何实际实现这一点。编译器在创建
Base
对象时,会向虚拟表添加一个隐藏指针
vptr
。虚拟表包含指向thunks的指针(为了简单起见,只需假设表中包含指向函数最终重写器的指针[1])。在这种情况下,
Base
对象将不包含成员数据,而只包含指向表的指针,该表包含指向函数
Base::f
的指针

Left
扩展
Base
时,将为
Left
创建一个新的vtable,该vtable中的指针设置为该级别的
f
的最终重写器,顺便说一句,它是
Base::f
,因此两个vtable中的指针(忽略蹦床)跳转到相同的实际实现。当构造类型为
Left
的对象时,首先初始化
Base
子对象,然后在初始化
Left
的成员之前(如果有)更新
Base::vptr
指针以引用
Left::vtable
(即,存储在
Base
中的指针指的是为
Left
定义的表)

在菱形的另一边,为
Right
创建的vtable包含一个thunk,该thunk最终调用
Right::f
。如果要创建
Right
类型的对象,将发生相同的初始化过程,
Base::vptr
将指向
Derived::f

现在我们进入最后一个对象
Bottom
。再次为类型
Bottom
生成一个vtable,该vtable与所有其他vtable一样,包含一个表示
f
的条目。编译器分析继承的层次结构,并确定
Right::f
覆盖
Base::f
,并且左分支上没有等效的覆盖,因此在
Bottom
的vtable中,表示
f
的指针指向
Right::f
。同样,在构建
Bottom
对象的过程中,
Base::vptr
更新为指向
Bottom
的vtable

如您所见,所有四个vtable都有一个
f
条目,程序中只有一个
f
,即使每个vtable中存储的值不同(最终重写器不同)


[1] thunk是一小段代码,如果需要,它可以调整
这个
指针(多重继承通常意味着需要它)然后将调用转发到实际重写。在单继承的情况下,
指针不需要更新,thunk消失,vtable中的条目直接指向实际函数。

问题不完全在于此。这里只有一个类重写方法并编译,而mon不会编译
new Bottom(23);
,在您的示例中,您没有接受
int
的构造函数。继承是一个不好的词。忘记它吧。没有继承。永不。好吧,因此
Bottom
对象关闭菱形,并查看具有函数f()的基类已定义。现在存在两种实现Base::f()和Right::f(),现在基于接口层次结构选择Right::f()。这准确吗?@Bober02:它足够接近除自己实现编译器之外的所有目的:)我已经更新了答案,其中包含了您可能想查看的实现细节。您在回答中提到,当创建Left时,它的基本对象vtable指向Left vtable。这是因为只有一个虚拟方法吗?如果在base中也有一个非虚拟方法,它将有一个单独的vtable right?另外,您说tre是一个f函数,但不同的重写器。我只看到2:Base::f和Right::f@Bober02:非虚拟函数不会影响vtable。我不记得确切的细节,但您可以假设每个类型都有一个vtable。在层次结构的每个级别上,该类型都有自己的vtable和