【问题标题】:C++ Inheritance/VTable questionsC++ 继承/VTable 问题
【发布时间】:2010-11-25 21:37:03
【问题描述】:

更新:将析构函数示例替换为直接方法调用示例。

嗨,

如果我有以下代码:

class a
{
public:
    virtual void func0(); // a has a VTable now
    void func1();
};
class b : public a
{
public:
    void func0() { a::func0(); }
    void func2();
};
  1. B 中是否有 VTable? B 没有虚函数,但从 b::func0() 调用 a::func0()
  2. func1 是否驻留在 VTable 中?它不是虚拟的。
  3. func2 是否驻留在 VTable 中?
  4. 如果 b::func0() 中没有 a::func0() 调用,上述答案会不会有所不同?

谢谢

【问题讨论】:

  • 如果你在这些问题中告诉我你正在使用什么编译器,我会很好。虚拟表是特定于实现的,尽管正在努力使其格式标准化。

标签: c++ class inheritance virtual vtable


【解决方案1】:

如果你声明虚函数,你也应该声明你的析构函数 virtual ;-)。

  1. B有一个虚表,因为它有一个虚函数,即func0()。如果在基类中声明一个函数(包括析构函数) virtual,则其所有派生类也将具有具有相同签名 virtual 的函数。这将导致他们拥有一个 vtable。此外,即使您没有在其中明确声明 func0,B 也会拥有 vtable。

  2. 非虚函数不通过虚表引用。

  3. 见 2。

  4. 没有。类的 vtable 是基于类声明构建的。不考虑类函数的主体(更不用说其他函数了)。所以B有一个vtable,因为它的函数func0()是虚函数。

还有一个棘手的细节,尽管这不是您问题的要点。您将函数 B::func0() 声明为内联。在gcc 编译器中,如果一个虚函数被声明为内联,它会在虚表中保留它的槽,该槽指向为该内联函数发出的一个特殊函数(这算作获取它的地址,这使得内联发出)。这意味着,函数是否内联不会影响 vtable 中的插槽数量及其对类的必要性。

【讨论】:

  • 已更新。此外,所以基本上如果一个函数在继承层次结构中的 any 基类中声明为虚拟,那么即使直接基类(上一级)没有将其标记为虚拟,该函数也是虚拟的?
  • @jameszhao00:也更新了答案。你说得对:如果任何间接基类(即当前类的某个父级的某个父级的父级......)声明了虚拟函数,那么它在当前类中也是虚拟的。请注意,重载函数( void f(int) 与 void f(double) 相比)被视为不同的函数。
【解决方案2】:
  1. 是的,因为它的基类有一个;它的析构函数也是虚拟的(即使你没有声明它是虚拟的),因为基类的析构函数是虚拟的。

  2. 没有。

  3. 没有。实际上我不认为当前的代码是合法的:编译器会在调用 B 析构函数之后调用 A 析构函数,即使你没有从 ~B 显式调用 ~A;所以我认为你不应该从 ~B 调用 ~A,即使编译器允许你这样做。

【讨论】:

  • 对不起。我不应该以析构函数为例。已更新。
【解决方案3】:

参考更新示例:

  1. 是的,b 有一个 vtable。请注意,b::func0() 是虚拟的(覆盖 a::func0()),即使您没有明确将其标记为虚拟。我猜是奇怪的 C++“漏洞”。
  2. 没有。非虚拟函数不驻留在 vtable 中。
  3. 见 2。
  4. 没有。你已经覆盖了 a:func0();是否调用 a::func0() 并不重要。

一些附加说明(依赖于编译器,但这些是非常常见的概括):

  • b 的每个实例都有一个指向 vtable 的指针,因为您是从具有虚函数的类派生而来的。
  • 即使您没有定义 b::func0(),情况也是如此。
  • 在这种情况下,编译器可能有 b 的实例指向 a 的静态 vtable,或者它可能为 b 创建一个静态 vtable em> 并用指向 a 成员的指针填充它。
  • 但它仍然是必需的,因此您可以通过指向a的指针正确访问b的实例。

【讨论】:

    【解决方案4】:
    • 如果基类函数是虚拟的,那么如果您在派生类中覆盖该函数,即使您没有明确指定,它也是隐式虚拟的。如果类有一个虚函数,那么它就有一个 v 表。
    • 只有虚函数存在于 vtable 中,function1 不会驻留在 vtable 中
    • function2 不会驻留在 vtable 中,原因与上述相同
    • vtable 的创建不取决于您是从基类还是从其他地方调用该函数。函数调用不决定 vtable 的创建。

    【讨论】:

      猜你喜欢
      • 2010-09-24
      • 2011-08-04
      • 1970-01-01
      • 2012-04-01
      • 2012-05-11
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多