首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-06 00:04
  • 3935
  • 11137
juejin.cn

在 C++ 中,virtual 关键字用于声明虚函数,表示该函数可以在派生类中被重写(override)。虚函数的主要作用是支持 多态(Polymorphism),即允许通过基类指针或引用调用派生类中重写的函数。

1. 虚函数的基本概念

当一个函数在基类中被声明为虚函数时,C++ 会为该函数提供一个机制,允许派生类重写该函数并且可以通过基类指针或引用调用派生类的实现。这样就实现了动态绑定,也就是在运行时决定调用哪个版本的函数。

2. virtual 的作用

  • 动态多态:virtual 函数使得程序能够在运行时决定调用哪个函数,而不是在编译时就决定。
  • 支持函数重写:派生类可以重写基类的虚函数,以提供特定的实现。

3. 基本示例

cpp
代码解读
复制代码
#include using namespace std; class Base { public: virtual void speak() { // 基类中的虚函数 cout << "Base class speaking" << endl; } }; class Derived : public Base { public: void speak() override { // 重写基类的虚函数 cout << "Derived class speaking" << endl; } }; int main() { Base* basePtr = new Derived(); // 基类指针指向派生类对象 basePtr->speak(); // 调用的是 Derived 类中的 speak() 函数 delete basePtr; return 0; }

输出:

kotlin
代码解读
复制代码
Derived class speaking

4. 如何工作:虚函数和多态

  • 在上面的示例中,speak() 函数在基类 Base 中被声明为 virtual。当我们通过 Base 类型的指针 basePtr 来调用 speak() 时,实际调用的是派生类 Derived 中重写的版本。这是因为 speak() 是虚函数,C++ 会根据对象的实际类型(即 Derived 类型)来选择合适的函数。

  • 如果没有使用 virtual,基类中的 speak() 会被调用,即使 basePtr 指向的是一个 Derived 类的对象。这样就没有实现多态。

5. 动态绑定与静态绑定的区别

  • 静态绑定:函数调用在编译时确定,函数的调用是基于编译时类型的。对于非虚函数,编译器根据指针或引用的声明类型来决定调用哪个函数。

  • 动态绑定:虚函数支持在运行时确定调用哪个函数。在运行时,程序根据指针或引用实际指向的对象类型来决定调用哪个版本的虚函数。

6. 虚函数表(Vtable)和虚函数指针(Vptr)

  • 每个类如果有虚函数,编译器会为该类生成一个虚函数表(Vtable)。这个表存储了该类的虚函数的地址。对于每个对象,编译器还会生成一个虚函数指针(Vptr),它指向该对象所属类的虚函数表。
  • 当通过基类指针调用虚函数时,程序会查找指针指向的对象的虚函数表,找到相应函数的地址并调用。

7. 虚析构函数

当一个类有虚函数时,通常该类也应该有虚析构函数。这是为了保证在删除基类指针指向派生类对象时,能够正确地调用派生类和基类的析构函数,避免内存泄漏或资源释放错误。

cpp
代码解读
复制代码
class Base { public: virtual ~Base() { // 虚析构函数 cout << "Base class destructor" << endl; } }; class Derived : public Base { public: ~Derived() override { // 重写析构函数 cout << "Derived class destructor" << endl; } }; int main() { Base* basePtr = new Derived(); // 基类指针指向派生类对象 delete basePtr; // 会调用 Derived 的析构函数,再调用 Base 的析构函数 return 0; }

输出:

kotlin
代码解读
复制代码
Derived class destructor Base class destructor

8. 虚函数的注意事项

  • 构造函数不能是虚函数:虽然类中的其他成员函数可以是虚函数,但构造函数不能是虚函数。构造函数是在对象创建时调用的,而虚函数是用于多态的,它需要依赖对象的完全构造。因此,构造函数不能进行多态调用。

  • 继承链中的虚函数:在继承层次中,派生类可以重写基类的虚函数。如果派生类没有重写某个虚函数,那么该虚函数在派生类中依然是虚的,并且会调用基类的版本。

  • 虚函数的性能开销:由于虚函数需要使用虚函数表来查找实际的函数地址,这可能会带来一些运行时开销,但通常这个开销是非常小的,不会影响性能。

总结

  • virtual 关键字用于声明虚函数,支持 多态。
  • 通过基类指针或引用调用虚函数时,程序会在运行时根据对象的实际类型选择合适的函数版本。
  • virtual 使得类层次结构中的函数可以被重写,支持动态绑定。
  • 使用虚函数时,通常需要考虑虚析构函数,以确保正确的资源释放。

虚函数是面向对象编程中实现多态和灵活性的重要机制,广泛应用于设计模式、插件架构、事件处理等场景中。

注:本文转载自juejin.cn的laughing66的文章"https://juejin.cn/post/7444471087834710025"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

142
代码人生
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top