8
class base {
public:
    void virtual fn(int i) {
        cout << "base" << endl;
    }
};

class der : public base{
    public:
    void  fn(char i) {
        cout << "der" << endl;
    }
};

int main() {

    base* p = new der;
    char i = 5;
    p->fn(i);
    cout << sizeof(base);
    return 0;
}

这里类中定义的函数 fn 的签名与类中定义base的函数的签名不同,尽管函数名称相同。因此,类中定义的函数隐藏了类函数。所以类 版本的 fn 不能被调用;没事。fn()derderbasefn()derp->fn(i)

我的观点是为什么要sizeof上课base,或者der如果4没有使用VTABLE 指针这里对VTABLE 指针有什么要求?

4

4 回答 4

7

请注意,这高度依赖于实现,并且可能因每个编译器而异。

存在的要求vtable是基类用于继承和扩展,从它派生的类可能会覆盖该方法。

Base 和 Derived 这两个类可能驻留在不同的翻译单元中,编译器在编译 Base 类时不会真正知道该方法是否会被覆盖。因此,如果它找到关键字virtual,它会生成vtable.

于 2012-02-02T09:13:33.897 回答
1

vtable 通常不仅用于虚函数,还用于在您执行某些操作dynamic_cast或程序访问该类时识别类类型type_info

如果编译器检测到没有虚拟函数被覆盖并且没有使用其他功能,它可以删除 vtable 指针作为优化。

显然编译器编写者认为这样做不值得。可能是因为它不会经常使用,并且因为您可以通过virtual从基类中删除来自己做。

于 2012-02-02T09:27:21.280 回答
1

编译器无法vtable从“基”类中优化成员变量,因为在同一个或另一个项目中可能存在另一个源文件,其中包含以下内容:

struct ived : base {
    ived() : p(new char[BIG_DATA_SIZE]) {}
    virtual ~ived();
    virtual void fn(int);
private:
    char* p;
};

析构函数并且fn可以在其他地方实现:

ived::~ived() { delete[] p; }

void ived::fn(int) {
    cout << "ived" << endl;
}

在另一个地方的某个地方可能会有这样的代码:

base* object = new ived;
ived->fn(0);
delete object;
cout << sizeof(base) << endl;

所以,会有两个问题:没有调用虚函数ived::fn,没有调用虚析构函数,所以BIG_DATA_SIZE没有删除。否则,sizeof(base)这里就不一样了。这就是为什么编译器总是vtable为任何具有虚拟成员函数或虚拟基类的类生成。

关于在派生类中调用析构函数,必须考虑:如果您有任何具有任何虚函数的类,该类也应声明一个虚析构函数。

于 2016-04-23T07:42:37.940 回答
0

继承是一种is-a关系。der是一个basebase有大小4der至少会有大小4vftableptr是 的成员base,它将是 的成员der

base有一个虚方法,所以不管你是否使用它,它都会有一个指向虚表的指针。

于 2012-02-02T09:18:08.413 回答