当派生类不重写虚函数时,为什么需要 vptr?
Why is a vptr required when the derived class doesn't override the virtual function?
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 的签名与类中定义的函数fn()
的签名不同der
尽管函数名相同。因此,der
类中定义的函数隐藏base
类函数fn()
。因此,类 der
版本的 fn 不能通过p->fn(i)
调用来调用;没事。
我的观点是,如果不使用 VTABLE 指针,为什么sizeof
类base
或der
4
?这里的VTABLE指针有什么要求?
请注意,这是高度依赖于实现的,并且可能因每个编译器而异。
存在 vtable
的要求是 Base 类用于继承和扩展,从它派生的类可能会重写该方法。
和 Derived 这两个类可能驻留在不同的翻译单元中,编译 Base 类时的编译器不会真正知道该方法是否会被覆盖。因此,如果它找到关键字virtual
它会生成 vtable
.
vtable 通常不仅用于虚函数,而且还用于在执行某些dynamic_cast
或程序访问类的type_info
时标识类类型。
如果编译器检测到没有虚拟函数被覆盖并且没有使用任何其他功能,它只是可以删除 vtable 指针作为优化。
显然,编译器编写者发现这样做不值得麻烦。可能是因为它不会经常使用,并且您可以通过从基类中删除virtual
来自己执行此操作。
无法从"基"类中优化出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
的原因。
关于在派生类中调用析构函数,必须将其视为必须的:如果您有任何具有任何虚函数的类,则该类还应声明虚拟析构函数。
是一种is-a
关系。 der
是base
. base
有大小4
,der
至少会有大小4
。 vftableptr
是base
的成员,它将是der
的成员。
base
有一个虚拟方法,因此无论您是否使用它,它都将具有指向虚拟表的指针。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么带有 vptr 的对象长 12 个字节?
- 如果在创建对象时创建了 VPTR,那么为什么具有虚拟功能的类的大小在 32 位系统上为 4,在 64 位机器上为 8
- 当派生类不重写虚函数时,为什么需要 vptr?
- 为什么vptr被存储为具有虚拟函数的类的内存中的第一个条目