当派生类不重写虚函数时,为什么需要 vptr?

发布于 2025-01-01 21:48:08 字数 737 浏览 0 评论 0原文

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;
}

尽管函数名称相同,但 base 类中定义的函数 fn 的签名与 der 类中定义的函数 fn() 的签名不同。 因此,在der类中定义的函数隐藏了base类函数fn()。因此 fn 的 der 版本不能通过 p->fn(i) 调用来调用;没关系。

我的观点是,如果不使用 VTABLE,为什么 sizeof class baseder4指针?这里VTABLE指针有什么要求?

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;
}

Here signature of function fn defined in base class is different from signature of function fn() defined in der class though function name is same.
Therefore, function defined in der class hides base class function fn(). So class der version of fn cannot be called by p->fn(i) call; It is fine.

My point is then why sizeof class base or der is 4 if there is no use of VTABLE pointer? What is requirement of VTABLE pointer here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

债姬 2025-01-08 21:48:08

请注意,这高度依赖于实现&每个编译器可能会有所不同。

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

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

Note that this is highly implementation dependent & might vary for each compiler.

The requirement for presence of vtable is that the Base class is meant for Inheritance and extension, and a class deriving from it might override the method.

The two classes Base and Derived might reside in different Translation Unit and the compiler while compiling the Base class won't really know if the method will be overidden or not. So, if it finds the keyword virtual it generates the vtable.

小矜持 2025-01-08 21:48:08

vtable 通常不仅用于虚函数,而且当您执行某些 dynamic_cast 或程序访问类的 type_info 时,它还用于标识类类型。

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

显然,编译器作者认为不值得这么麻烦。可能是因为它不会经常使用,而且您可以通过从基类中删除 virtual 来自己完成此操作。

The vtable is usually not only used for virtual functions, but it is also used to identify the class type when you do some dynamic_cast or when the program accesses the type_info for the class.

If the compiler detects that no virtual functions are ever overridden and none of the other features are used, it just could remove the vtable pointer as an optimization.

Obviously the compiler writer hasn't found it worth the trouble of doing this. Probably because it wouldn't be used very often, and because you can do it yourself by removing the virtual from the base class.

时光与爱终年不遇 2025-01-08 21:48:08

编译器无法优化“基”类中的 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

关于在派生类中调用析构函数,必须将其视为必须:如果您有任何带有虚函数的类,则该类也应声明虚拟析构函数。

The compiler cannot optimize out vtable member variable out of 'base' class, because there could be another source file within the same or another project which would contain the following:

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

The destructor and fn could be implemented somewhere else:

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

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

And somewhere in another place there could be code like this:

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

So, there would be two problems: virtual function ived::fn not called, virtual destructor not called, so BIG_DATA_SIZE not deleted. Otherwise, sizeof(base) here would be different. That is why compilers always generate vtable for any class with a virtual member function or a virtual base class.

Regarding calling destructors in derived classes, it must be considered as a must: if you have any class with any virtual function, that class shall also declare a virtual destructor.

南冥有猫 2025-01-08 21:48:08

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

base 有一个虚方法,因此它会有一个指向虚表的指针,无论你是否使用它。

Inheritance is a is-a relationship. der is-a base. base has size 4, der will have at least size 4. vftableptr is a member of base, it will be a member of der.

base has a virtual method, so it will have a pointer to the virtual table, regardless of whether you use it or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文