gpt4 book ai didi

c++ - C++中的虚拟继承

转载 作者:IT老高 更新时间:2023-10-28 23:14:55 25 4
gpt4 key购买 nike

我在阅读 C++ 中的虚拟继承时在一个网站上发现了这个

当使用多重继承时,有时需要使用虚拟继承。一个很好的例子是标准 iostream 类层次结构:

//Note: this is a simplified description of iostream classes

class ostream: virtual public ios { /*..*/ }
class istream: virtual public ios { /*..*/ }

class iostream : public istream, public ostream { /*..*/ }
//a single ios inherited

C++ 如何确保只存在一个虚拟成员的单个实例,而不考虑从它派生的类的数量? C++ 使用额外的间接层来访问虚拟类,通常是通过指针。换句话说,iostream 层次结构中的每个对象都有一个指向 ios 对象共享实例的指针。额外的间接级别会产生轻微的性能开销,但付出的代价很小。

我对以下陈述感到困惑:

C++ 使用额外的间接级别来访问虚拟类,通常通过指针的方式

谁能解释一下?

最佳答案

要解决的基本问题是,如果将指向最派生类型的指针强制转换为指向其基类之一的指针,则该指针必须引用内存中的地址,代码可以从该地址中找到该类型的每个成员不知道派生类型。对于非虚拟继承,这通常是通过具有精确的布局来实现的,而这又是通过包含一个基类子对象然后添加派生类型的额外位来实现的:

struct base { int x; };
struct derived : base { int y };

派生的布局:

--------- <- base & derived start here
x
---------
y
---------

如果您添加第二个派生类型和一个最派生类型(同样,没有虚拟继承),您会得到如下结果:

struct derived2 : base { int z; };
struct most_derived : derived, derived 2 {};

使用这种布局:

--------- <- derived::base, derived and most_derived start here
x
---------
y
--------- <- derived2::base & derived2 start here
x
---------
z
---------

如果您有 most_derived对象,然后绑定(bind) derived2 类型的指针/引用它将指向标有 derived2::base 的行.现在,如果从 base 继承是虚拟的,那么应该有一个 base 的实例。 .为了便于讨论,假设我们天真地删除了第二个 base :

--------- <- derived::base, derived and most_derived start here
x
---------
y
--------- <- derived2 start here??
z
---------

现在的问题是,如果我们获得指向 derived 的指针它的布局与原始布局相同,但如果我们尝试获取指向 derived2 的指针布局会有所不同,代码在 derived2将无法找到 x成员。我们需要做一些更聪明的事情,这就是指针发挥作用的地方。通过添加一个指向每个虚拟继承对象的指针,我们得到了这样的布局:

---------  <- derived starts here
base::ptr --\
y | pointer to where the base object resides
--------- <-/
x
---------

同样适用于 derived2 .现在,以额外的间接为代价,我们可以找到 x子对象通过指针。当我们可以创建 most_derived具有单个基础的布局,它可能如下所示:

---------          <- derived starts here
base::ptr -----\
y |
--------- | <- derived2
base::ptr --\ |
z | |
--------- <--+-/ <- base
x
---------

现在输入 derivedderived2现在了解如何访问基本子对象(只需取消引用 base::ptr 成员对象),同时您有一个 base 实例.如果任一中间类中的代码访问 x他们可以这样做 this->[hidden base pointer]->x ,这将在运行时解决到正确的位置。

这里的重要一点是在 derived 编译的代码/derived2 layer 可以与该类型的对象或任何派生对象一起使用。如果我们写第二个 most_derived2继承顺序颠倒的对象,则它们的布局为yz可以交换,以及指向 derived 的指针的偏移量或 derived2 base 的子对象子对象会有所不同,但访问 x 的代码仍然是一样的:取消引用你自己的隐藏基指针,保证如果 derived 中的方法是最终的覆盖者,并且访问 base::x那么无论最终布局如何,它都会找到它。

关于c++ - C++中的虚拟继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5179854/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com