电话
400 9058 355
虚函数必须在基类中用virtual显式声明,否则不触发动态绑定;纯虚函数使类成为抽象类;析构函数需virtual以防资源泄漏;多态须通过指针或引用,避免对象切片;vtable和vptr实现动态绑定;override和final提升安全性。
virtual 显式声明不加 virtual 的成员函数即使签名相同,也不会触发动态绑定。编译器只看指针/引用的静态类型,调用的是该类型定义的版本,不是实际对象的类型。
常见错误是忘记在基类声明 virtual,或者误以为“子类重写就自动多态”——C++ 不自动推导,必须显式标记。
virtual 只需出现在基类声明中,派生类重写时加不加都可(但建议加上,提高可读性)virtual void func() = 0;,含纯虚函数的类即抽象类,不能实例化virtual,否则派生类部分不会被析构值传递会触发对象切片(slicing),丢失派生类特有成员和虚函数表信息,调用的永远是基类版本。
Base b = Derived(); // 切片!b 只剩 Base 部分 b.func(); // 静态绑定,调用 Base::func() Base* ptr = new Derived(); ptr->func(); // 动态绑定,调用 Derived::func()
Base* 或 Base& 才能触发动态绑定Base 对象本身、Base 类型的局部变量、函数按值传参,全部走静态绑定每个含虚函数的类编译时生成一张虚函数表(vtable),存放该类所有虚函数的地址;每个对象实例开头隐式插入一个虚指针(vptr),指向其所属类的 vtable。
运行时,通过 ptr->func() 调用时,编译器生成的代码实际是:(*ptr->vptr[索引])(ptr) —— 先取 vptr,再查表,最后调用。
普通函数多一次内存寻址(vptr → vtable → 函数地址),有轻微开销,但现代 CPU 分支预测能缓解不加 override 时,拼错函数名、参数类型不匹配、const 修饰不一致,都会导致“看似重写实则新增”,失去多态效果且无编译错误。
class Base { virtual void foo(int) const; };
class Derived : public Base {
void foo(int) {} // 缺 const → 新函数,非重写!
void foo(int) const override; // 正确:编译器检查是否真能重写
void bar() const override; // 错误:Base 没有 bar → 编译失败
};override 强制编译器验证:该函数是否确实重写了基类虚函数final 加在函数后(virtual void f() final;)禁止进一步重写;加在类后(class D final : B {})禁止继承虚函数多态看似简单,真正容易出问题的地方在于:对象生命周期管理(尤其是 virtual 析构)、切片场景的误用、以及未加 override 导致的静默失效。这些都不是语法错误,而是逻辑陷阱,调试时很难一眼发现。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...