

新闻资讯
技术学院虚函数必须在基类中用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,再查表,最后调用。
不加 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 导致的静默失效。这些都不是语法错误,而是逻辑陷阱,调试时很难一眼发现。