☰
虚函数和 RTTI实现运行时多态
2026/10/8 9:37:06 网站建设 项目流程

虚函数和RTTI是 C++ 实现运行时多态的两大核心机制。


1. 虚函数(Virtual Function)

什么是虚函数?

在基类中用virtual声明的成员函数。当通过基类指针或引用调用时,实际执行的是对象真正类型(动态类型)对应的函数版本,而不是指针/引用声明的类型(静态类型)。

核心作用

实现运行时多态(动态绑定)。

简单原理(实现层面)
  • 含有虚函数的类会生成一张虚函数表(vtable)。
  • 每个对象会多一个隐藏的指针vptr,指向自己类的 vtable。
  • 调用虚函数时,通过 vptr 找到正确的函数地址再执行。
示例
#include<iostream>classAnimal{public:virtualvoidspeak()const{// 虚函数std::cout<<"Animal speaks\n";}virtual~Animal()=default;// 强烈建议虚析构};classDog:publicAnimal{public:voidspeak()constoverride{// 重写std::cout<<"Woof!\n";}};classCat:publicAnimal{public:voidspeak()constoverride{std::cout<<"Meow!\n";}};intmain(){Animal*a1=newDog();Animal*a2=newCat();a1->speak();// 输出 Woof!(按动态类型调用)a2->speak();// 输出 Meow!deletea1;deletea2;}
重要规则
点说明
虚析构函数通过基类指针delete时,必须虚析构,否则只调用基类析构,导致资源泄漏
overrideC++11 推荐使用,明确表示重写,防止拼写错误
纯虚函数virtual void f() = 0;使类成为抽象类,不能实例化
非虚函数始终按静态类型调用,不会动态分派

2. RTTI(Runtime Type Information)

什么是 RTTI?

运行时类型信息。允许程序在运行时查询对象的真实类型。

C++ 提供两个主要工具:

  1. typeid
  2. dynamic_cast

前提:类型必须是多态类型(至少有一个虚函数),否则typeid和dynamic_cast只能看到静态类型。

2.1typeid

返回const std::type_info&,可用来比较类型。

#include<iostream>#include<typeinfo>Animal*p=newDog();if(typeid(*p)==typeid(Dog)){std::cout<<"这是一只狗\n";}std::cout<<typeid(*p).name()<<'\n';// 实现定义(可能是 "3Dog" 或 "class Dog")

注意:typeid对引用和指针解引用后的对象才有效地获取动态类型。

2.2dynamic_cast(安全向下转型)

在运行时检查转型是否合法:

  • 成功 → 返回正确的指针/引用
  • 失败 → 指针返回nullptr,引用抛出std::bad_cast
Animal*p=newDog();// 向下转型if(Dog*d=dynamic_cast<Dog*>(p)){d->speak();// 安全使用// 可以调用 Dog 特有的成员}else{std::cout<<"不是 Dog\n";}// 引用版本(失败会抛异常)try{Dog&d=dynamic_cast<Dog&>(*p);}catch(conststd::bad_cast&e){std::cout<<"转型失败\n";}
dynamic_cast的常见用途
  • 安全地从基类指针转回派生类指针
  • 跨继承体系转型(多继承时)
  • 判断对象是否属于某个类型

虚函数 vs RTTI 对比

特性虚函数RTTI(typeid / dynamic_cast)
目的调用正确的函数版本查询/检查真实类型
性能很快(一次间接调用)稍慢(需要查类型信息)
依赖虚函数表同样依赖虚函数(多态类型)
使用场景日常多态调用需要知道具体类型时(较少用)

使用建议

  1. 优先使用虚函数
    绝大多数多态场景用虚函数就够了,更清晰、更高效。

  2. 少用 RTTI
    频繁使用dynamic_cast或typeid通常是设计不够好的信号(可以用虚函数或 visitor 模式替代)。

  3. 必须虚析构
    只要类可能被基类指针删除,就应该把析构函数声明为虚函数。

  4. 抽象基类
    如果基类不应该被实例化,就把关键接口写成纯虚函数。


一句话总结:

  • 虚函数→ 让“调用哪个函数”在运行时决定
  • RTTI→ 让“对象到底是什么类型”在运行时可知

两者都依赖“多态类型”(有虚函数),共同支撑 C++ 的运行时多态能力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询