C++ 我在哪里可以找到关于C++;有状态虚拟基?

C++ 我在哪里可以找到关于C++;有状态虚拟基?,c++,C++,我看了一下报纸,读了他们的解释,但我在寻找一些额外的信息 感谢您提供的任何其他详细信息 斯坦利·利普曼的书对这一主题进行了深入的探讨(虽然过时了,但仍然有效)。斯坦利·利普曼的书对这一主题进行了深入的探讨(虽然过时了,但仍然有效)。虚拟性是关于间接性的。让我们从简单开始: struct Foo { void bar(int, bool) {} } x; x.bar(12, false); 在这里,对实例x的Foo::bar()调用在编译时是完全已知的,并且是静态解析的:一个固定函数,它被赋予实

我看了一下报纸,读了他们的解释,但我在寻找一些额外的信息


感谢您提供的任何其他详细信息

斯坦利·利普曼的书对这一主题进行了深入的探讨(虽然过时了,但仍然有效)。

斯坦利·利普曼的书对这一主题进行了深入的探讨(虽然过时了,但仍然有效)。

虚拟性是关于间接性的。让我们从简单开始:

struct Foo { void bar(int, bool) {} } x;
x.bar(12, false);
在这里,对实例
x
Foo::bar()
调用在编译时是完全已知的,并且是静态解析的:一个固定函数,它被赋予实例引用和函数参数。函数名,调用,完成。到目前为止没有问题

继续:

struct Boo { virtual void bar(char, float) = 0; };
extern Boo * foreign_function();

Boo * p = foreign_function();
p->bar('a', -1.5);
这次,无法在编译时知道
bar()
调用应该去哪里。解决此问题的唯一方法是添加一个间接级别,允许您查找此成员函数的所有可能重写,并在运行时根据
*p
的动态类型选择正确的重写。这次我们从函数名开始,在运行时执行查找,然后进行调用。这种模式应该仍然相当熟悉

这里的要点是,只要知道
*p
的动态类型是(非虚拟)基
Boo
的一个子类型就足够了,这样我们只需一次查找即可实现这一点(例如,指向与
Boo
兼容的表的vtable指针)

现在来谈谈大鱼:

struct Voo { virtual void doo(double, void *) = 0; };
struct Left  : virtual Voo { virtual void doo(double, void *); } };
struct Right : virtual Voo { virtual void doo(double, void *); } };
struct Most : Left, Right  { virtual void doo(double, void *); } };

Left * p = /* address of a Most object, say */;
p->doo(0.1, nullptr);
我们已经知道,我们不知道
doo()
应该去哪里,我们必须在运行时查找它。然而,简单的一步间接寻址已不再可能。尽管
Left
Voo
的子类,
Right
也是
Voo
的子类,但
*p
的实际
Voo
基本子对象实际上不是
Left
Right
子对象的子对象(唯一!)虚拟子对象直接属于
Most
(或任何派生最多的对象)。在实现术语中,单个vtable指针是不好的,因为我们不需要
Left
的vpointer,也不需要
Right
的vptr。相反,我们需要实际对象具有的vpointer

所以现在我们发现自己处于一种熟悉的情况:我们需要查找一些只有在运行时才能知道的内容。这一次我们需要查找的是实际的虚拟基地。所以这个过程是这样的:函数名,在运行时查找virtualbase,在virtualbase中查找virtual函数,然后进行调用。(在虚拟性的典型vtable实现中,通常通过“thunk”或“指向指针的指针”进行额外的查找。)

简而言之,“虚拟”意味着“在运行时确定”


(这不会强制编译器生成运行时代码。如果在编译时可以证明分派的目标是已知的,则调用可能会被反虚拟化。但程序的行为是“好像”。

虚拟性是关于间接寻址的。让我们从简单开始:

struct Foo { void bar(int, bool) {} } x;
x.bar(12, false);
在这里,对实例
x
Foo::bar()
调用在编译时是完全已知的,并且是静态解析的:一个固定函数,它被赋予实例引用和函数参数。函数名,调用,完成。到目前为止没有问题

继续:

struct Boo { virtual void bar(char, float) = 0; };
extern Boo * foreign_function();

Boo * p = foreign_function();
p->bar('a', -1.5);
这次,无法在编译时知道
bar()
调用应该去哪里。解决此问题的唯一方法是添加一个间接级别,允许您查找此成员函数的所有可能重写,并在运行时根据
*p
的动态类型选择正确的重写。这次我们从函数名开始,在运行时执行查找,然后进行调用。这种模式应该仍然相当熟悉

这里的要点是,只要知道
*p
的动态类型是(非虚拟)基
Boo
的一个子类型就足够了,这样我们只需一次查找即可实现这一点(例如,指向与
Boo
兼容的表的vtable指针)

现在来谈谈大鱼:

struct Voo { virtual void doo(double, void *) = 0; };
struct Left  : virtual Voo { virtual void doo(double, void *); } };
struct Right : virtual Voo { virtual void doo(double, void *); } };
struct Most : Left, Right  { virtual void doo(double, void *); } };

Left * p = /* address of a Most object, say */;
p->doo(0.1, nullptr);
我们已经知道,我们不知道
doo()
应该去哪里,我们必须在运行时查找它。然而,简单的一步间接寻址已不再可能。尽管
Left
Voo
的子类,
Right
也是
Voo
的子类,但
*p
的实际
Voo
基本子对象实际上不是
Left
Right
子对象的子对象(唯一!)虚拟子对象直接属于
Most
(或任何派生最多的对象)。在实现术语中,单个vtable指针是不好的,因为我们不需要
Left
的vpointer,也不需要
Right
的vptr。相反,我们需要实际对象具有的vpointer

所以现在我们发现自己处于一种熟悉的情况:我们需要查找一些只有在运行时才能知道的内容。这一次我们需要查找的是实际的虚拟基地。所以这个过程是这样的:函数名,在运行时查找virtualbase,在virtualbase中查找virtual函数,然后进行调用。(在虚拟性的典型vtable实现中,通常通过“thunk”或“指向指针的指针”进行额外的查找。)

简而言之,“虚拟”意味着“在运行时确定”


(这并不强制编译器生成运行时代码。如果可以证明在编译时已知分派的目标,则调用可能会被反虚拟化。但程序的行为是“好像”。

我从未听说过这个术语,但我推测这是一个具有虚拟成员函数的基类