什么时候是在C ++中创建的vtable? [英] When is a vtable created in C++?

查看:128
本文介绍了什么时候是在C ++中创建的vtable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译器究竟创建了一个虚函数表?



1)当类包含至少一个虚函数时。



2)当立即基类包含至少一个虚函数时。



OR



与此有关的一个相关问题:
是可能的放弃C ++层次结构中的动态分派?



例如请考虑以下示例。

  #include< iostream> 
using namespace std;
class A {
public:
virtual void f();
};
class B:public A {
public:
void f();
};
class C:public B {
public:
void f();
};

哪些类将包含V表?



由于B没有将f()声明为虚拟的,C类是否获得动态多态性?

解决方案

vtables是具体实现的(它们是),如果使用vtable:每个类都有唯一的vtables。即使 B :: f C :: f 没有被声明为虚拟的,因为在基类的虚方法上有一个匹配的签名( / em>), B :: f C :: f 都是隐式虚拟的。因为每个类至少有一个唯一的虚方法( B :: f 覆盖 A 实例和 :f 类似于 C 实例),你需要三个vtables。



细节。重要的是你是否有虚拟调度。您不必使用虚拟分派,通过明确指定调用哪个函数,但这通常只在实现虚拟方法时有用(例如调用基本方法)。示例:

  struct B {
virtual void f(){}
virtual void g }
};

struct D:B {
virtual void f(){//即使未声明也将隐式虚拟
B :: f();
// do D-specific stuff
}
virtual void g(){}
};

int main(){
{
B b; b.g(); b.B :: g(); // both call B :: g
}
{
D d;
B& b = d;
b.g(); // calls D :: g
b.B :: g(); //调用B :: g

b.D :: g(); // not allowed
d.D :: g(); // calls D :: g

void(B :: * p)()=& B :: g;
(b。* p)(); //调用D :: g
//通过函数指针调用总是使用虚拟分派
//(如果指向的函数是虚函数)
}
return 0;
}

但不引用我对这些,我可能错过了一些边缘情况:




  • 如果一个类有虚方法或虚拟基础,即使继承,则实例必须有一个vtable指针。

  • 如果一个类声明非继承的虚方法(例如当它没有基类时)

  • 如果一个类与第一个基类具有不同的重写方法集合,那么它必须有自己的vtable,并且不能重用基类。

  • 如果一个类有多个基类,第二个或后面的基类有虚方法:

    • 如果没有更早的基础具有虚拟方法,并且空基本优化应用于所有较早的基础,则将此基础作为第一个基础类。

    • 否则,类必须有自己的vtable。


  • 如果一个类有任何虚拟基类,它必须有自己的vtable。



请记住,vtable类似于类的静态数据成员,实例只有指向这些类的指针。



另请参阅综合文章 C ++:在胡德 (3月1994)。 Try Google )如果该链接失效。)



重复使用vtable的示例:

  struct B {
virtual void f();
};
struct D:B {
//不覆盖B :: f
//没有其他虚拟的自己
void g(); //仍然可能有自己的非虚拟
int n; // and data members
};

特别注意 B 的dtor不是虚拟的这是可能是实际代码中的错误),但在此示例中, 实例将指向与 B 实例相同的vtable。 p>

When exactly does the compiler create a virtual function table?

1) when the class contains at least one virtual function.

OR

2) when the immediate base class contains at least one virtual function.

OR

3) when any parent class at any level of the hierarchy contains at least one virtual function.

A related question to this: Is it possible to give up dynamic dispatch in a C++ hierarchy?

e.g. consider the following example.

#include <iostream>
using namespace std;
class A {
public:
  virtual void f();
};
class B: public A {
public:
  void f();
};
class C: public B {
public:
  void f();
};

Which classes will contain a V-Table?

Since B does not declare f() as virtual, does class C get dynamic polymorphism?

解决方案

Beyond "vtables are implementation-specific" (which they are), if a vtable is used: there will be unique vtables for each of your classes. Even though B::f and C::f are not declared virtual, because there is a matching signature on a virtual method from a base class (A in your code), B::f and C::f are both implicitly virtual. Because each class has at least one unique virtual method (B::f overrides A::f for B instances and C::f similarly for C instances), you need three vtables.

You generally shouldn't worry about such details. What matters is whether you have virtual dispatch or not. You don't have to use virtual dispatch, by explicitly specifying which function to call, but this is generally only useful when implementing a virtual method (such as to call the base's method). Example:

struct B {
  virtual void f() {}
  virtual void g() {}
};

struct D : B {
  virtual void f() { // would be implicitly virtual even if not declared virtual
    B::f();
    // do D-specific stuff
  }
  virtual void g() {}
};

int main() {
  {
    B b; b.g(); b.B::g(); // both call B::g
  }
  {
    D d;
    B& b = d;
    b.g(); // calls D::g
    b.B::g(); // calls B::g

    b.D::g(); // not allowed
    d.D::g(); // calls D::g

    void (B::*p)() = &B::g;
    (b.*p)(); // calls D::g
    // calls through a function pointer always use virtual dispatch
    // (if the pointed-to function is virtual)
  }
  return 0;
}

Some concrete rules that may help; but don't quote me on these, I've likely missed some edge cases:

  • If a class has virtual methods or virtual bases, even if inherited, then instances must have a vtable pointer.
  • If a class declares non-inherited virtual methods (such as when it doesn't have a base class), then it must have its own vtable.
  • If a class has a different set of overriding methods than its first base class, then it must have its own vtable, and cannot reuse the base's. (Destructors commonly require this.)
  • If a class has multiple base classes, with the second or later base having virtual methods:
    • If no earlier bases have virtual methods and the Empty Base Optimization was applied to all earlier bases, then treat this base as the first base class.
    • Otherwise, the class must have its own vtable.
  • If a class has any virtual base classes, it must have its own vtable.

Remember that a vtable is similar to a static data member of a class, and instances have only pointers to these.

Also see the comprehensive article C++: Under the Hood (March 1994) by Jan Gray. (Try Google if that link dies.)

Example of reusing a vtable:

struct B {
  virtual void f();
};
struct D : B {
  // does not override B::f
  // does not have other virtuals of its own
  void g(); // still might have its own non-virtuals
  int n; // and data members
};

In particular, notice B's dtor isn't virtual (and this is likely a mistake in real code), but in this example, D instances will point to the same vtable as B instances.

这篇关于什么时候是在C ++中创建的vtable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆