无继承的普通类中声明的virtual方法是否真的具备虚函数特性?
结论
两种写法并不等效,即便类A当前没有任何派生类,被virtual标记的函数依然是符合C++标准定义的虚函数,两种实现存在多处本质区别。
核心差异点
- 内存布局不同
包含虚函数的类会自动生成对应虚函数表(vtable),且每个类实例会隐含一个虚表指针(vptr)指向所属类的虚表,直接影响类实例的内存占用。以64位环境为例,无虚函数的A类实例大小至少为1字节,带虚函数的A类实例大小通常为8字节。
你可以通过这段代码直接验证差异:#include <iostream> class AWithVirtual { virtual void f() {} }; class AWithoutVirtual { void f() {} }; int main() { std::cout << sizeof(AWithVirtual) << std::endl; // 64位环境通常输出8 std::cout << sizeof(AWithoutVirtual) << std::endl; // 通常输出1 return 0; } - 函数调用逻辑不同
无virtual修饰的成员函数是静态绑定,调用地址在编译期就已经确定;带virtual修饰的成员函数是动态绑定,运行时需要通过虚表寻址找到对应的函数入口再调用,哪怕没有派生类这个逻辑也不会改变。 - 可扩展性不同
如果后续你新增派生类继承A,带virtual修饰的f()天然支持多态特性,派生类重写f()后可以通过基类指针调用到派生类的实现,无virtual修饰的版本则不支持该能力。
补充说明
C标准并没有规定“没有派生类的虚函数会自动退化为普通函数”,只要你显式加了virtual关键字,对应的属性就会永久生效,不会因为当前没有派生场景就被编译器优化掉。哪怕开启高等级优化,虚表、vptr和动态绑定的逻辑也会默认保留,只有部分编译器在能100%确认该类不会被派生、不会有多态调用场景时才会做特殊优化,这属于编译器特定的扩展行为,不属于C标准规定的通用规则。
内容的提问来源于stack exchange,提问作者user1899020
相关产品推荐
相关产品推荐

