【C++】C++的多态是个啥,咋用的?

C++的多态是个啥,咋用的?

今天我来讲:多态(Polymorphism)。有人说它是面向对象的灵魂,那么,多态到底是个啥?怎么用?


一、多态是个啥?

"多态"这个词来自希腊语,意思是"多种形态"。放在编程世界里,就是:同一段代码,在不同的对象上,可以表现出不同的行为

举个例子,假设我们有一个 Animal 类,还有两个子类 DogCat

cpp 复制代码
class Animal {
public:
    virtual void speak() {
        std::cout << "动物叫" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() override {
        std::cout << "汪汪" << std::endl;
    }
};

class Cat : public Animal {
public:
    void speak() override {
        std::cout << "喵喵" << std::endl;
    }
};

如果写一段代码:

cpp 复制代码
Animal* p1 = new Dog();
Animal* p2 = new Cat();

p1->speak();  // 输出:汪汪
p2->speak();  // 输出:喵喵

你会发现,同样是 speak(),但是不同对象的表现不一样,这就是多态


二、多态分哪几种?

在 C++ 里,多态主要分两类:

  • 编译时多态(静态多态) 例如函数重载、模板。这是在编译期就决定了调用哪个函数。
  • 运行时多态(动态多态) 也就是我们常说的虚函数 + 继承。这是运行期根据对象的真实类型决定调用哪个函数。

今天我们重点聊 运行时多态,因为这是面向对象的核心。


三、多态的三个必要条件

想在 C++ 里实现运行时多态,需要满足三个条件:

  1. 有继承(基类和派生类)
  2. 基类方法是虚函数virtual 关键字)
  3. 通过基类指针或引用调用方法

比如:

cpp 复制代码
Animal* p = new Dog();  // 基类指针指向派生类
p->speak();             // 发生多态

如果不用 virtual,就没有多态,调用的永远是 Animal 里的 speak()


四、底层虚函数表(vtable)!

为什么 C++ 能在运行时决定调用哪个函数? 答案是 虚函数表机制(Virtual Table)

编译器在处理含有虚函数的类时,会做几件事:

  1. 为每个含虚函数的类生成一张 虚函数表(vtable),里面存放该类的虚函数地址。
  2. 在对象里存一个 虚表指针(vptr),指向对应类的虚表。
  3. 当你调用虚函数时,编译器会通过 vptr 查虚表,找到正确的函数地址再执行。

简化后的示意图:

css 复制代码
Animal 对象:
[vptr] -> [Animal::speak]

Dog 对象:
[vptr] -> [Dog::speak]

所以,p->speak() 运行时调用哪一个函数,取决于 vptr 指向哪张虚表。


性能影响大吗?

虚函数调用需要一次额外的指针间接寻址,比普通函数慢一点,但代价很小。

放心用吧,你电脑撑得住~


五、用多态的正确姿势

1. 析构函数要是虚的

如果基类用指针指向派生类对象,那么基类析构函数必须是虚函数,否则会内存泄漏。

cpp 复制代码
class Animal {
public:
    virtual ~Animal() {}  // 一定要 virtual!!!
};

如果不用 virtualdelete p 时只会调用基类析构函数,派生类资源不会释放。


2. 避免 slicing(对象切片)

如果你用值传递,而不是指针或引用,多态会失效。

cpp 复制代码
Dog d;
Animal a = d;  // 切片:只拷贝 Animal 部分
a.speak();     // 输出"动物叫"

3. 多态和模板结合

C++ 的 模板 + 多态 结合非常强大,可以做到编译时多态 + 运行时多态配合,用在策略模式、插件系统等场景。


六、总结~

C++ 的多态就是运行时根据对象的实际类型,动态决定调用哪个方法 ,它通过 虚函数表 实现,是面向对象编程的核心特性之一。

正确使用多态可以让代码更灵活、更易扩展,但也要注意析构、性能和设计合理性。

相关推荐
郭东东1 分钟前
用数据工程与策略,推动模型持续进化|字节跳动招聘全栈研发工程师 - AI 数据与安全
llm·ai编程·招聘
道一云黑板报6 分钟前
告别提示词工程:为什么“循环工程”才是 AI 编程的未来?
人工智能·驱动开发·软件工程·ai编程
磊 子9 分钟前
C++设计模式
javascript·c++·设计模式
可乐ea10 分钟前
【Spring Boot + MyBatis|第7篇】JWT 登录认证与拦截器实现
java·spring boot·后端·mybatis·状态模式
沉默王二18 分钟前
面试官坏笑:“你用 AI 编程一年了,怎么保证 Claude Code 写出来的代码是对的?”我:“直接上 Claude Fable 5 啊!”
agent·ai编程·claude
西安邮电大学29 分钟前
有关栈的经典算法题
java·后端·其他·算法·面试
雨辰AI36 分钟前
从零搭建大模型本地运行环境|Python+CUDA 基础配置避坑大全
大数据·开发语言·人工智能·python·ai·ai编程·ai写作
h_a_o777oah40 分钟前
【算法专项】扩展域并查集:原理详解及解决大部分种类并查集问题(洛谷P5937 P2024 C++代码)
数据结构·c++·算法·acm·并查集·扩展域·逻辑建模
摇滚侠1 小时前
SpringMVC 入门到实战 配置类替换 XML 配置文件 86-91
xml·java·后端·spring·maven·intellij-idea
我登哥MVP1 小时前
SpringCloud Alibaba 核心组件解析:服务注册与发现(Nacos)
java·spring boot·后端·spring·spring cloud·java-ee·maven