虚函数实现多态的核心在于编译器为含虚函数的类生成虚函数表(vtable)并维护vptr,运行时通过vptr动态绑定函数地址;空类加virtual函数后sizeof变为指针宽度(如x64下8字节),可初步验证虚表存在。
核心在于:编译器为含虚函数的类生成虚函数表(vtable),每个对象头存储指向该表的指针(vptr)。运行时通过 vptr 找到正确的函数地址,而非编译期绑定。
注意:只有被声明为 virtual 的成员函数才进虚表;普通重载、静态成员函数、构造函数不参与多态;析构函数建议显式加 virtual,否则 delete 基类指针可能漏掉派生类清理逻辑。
最直接的办法是看对象大小是否“异常”——比如空类通常占 1 字节,但若加了 virtual 函数,sizeof 会变成指针宽度(x64 下为 8 字节):
struct A { virtual void f() {} };
struct B { void f() {} };
static_assert(sizeof(A) == 8); // 通常成立
static_assert(sizeof(B) == 1); // 通常成立
更可靠的方式是用调试器观察对象内存布局(如 VS 的内存窗口),或借助编译器扩展(GCC 的 -fdump-class-hierarchy)输出虚表结构。

vptr。
override 但签名不匹配 → 编译报错,不会进虚表本质是让 vptr 指向错误的虚表,或让对象处于未定义状态:
memcpy 或 memset 拷贝/清零含虚函数的对象 → vptr 可能被覆盖或失效vptr 指向当前正在构造/析构的类的虚表,不会动态绑定到最终派生类vptr 指向野内存虚表本身是只读数据段内容,但误操作对象内存比搞错虚表结构更容易出问题——多数崩溃不是虚表不存在,而是 vptr 不再可信。