C++多态全面解析:从概念到实现

1. 多态的基本概念

1.1 什么是多态?

多态(polymorphism)是面向对象编程的三大特性之一,指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。

两种多态类型:

  • 编译时多态(静态多态):函数重载、模板

  • 运行时多态(动态多态):通过虚函数和继承实现

1.2 实际应用场景

  • 买票行为:普通人全价,学生半价,军人优先

  • 动物叫声:猫"喵喵",狗"汪汪"

  • 交通工具:汽车行驶,飞机飞行

2. 多态的实现条件

2.1 必须满足的条件

cpp

复制代码
class Person {
public:
    virtual void BuyTicket() {  // 1. 必须是虚函数
        cout << "买票-全价" << endl;
    }
};

class Student : public Person {
public:
    virtual void BuyTicket() override {  // 2. 派生类必须重写虚函数
        cout << "买票-半价" << endl;
    }
};

void Func(Person& people) {  // 3. 必须是基类的指针或引用
    people.BuyTicket();  // 4. 调用虚函数
}

2.2 为什么必须是基类指针/引用?

基类指针/引用可以:

  1. 指向基类对象

  2. 指向派生类对象(向上转型)

  3. 实现统一接口,不同实现

3. 虚函数详解

3.1 虚函数声明

cpp

复制代码
class Base {
public:
    virtual void func();  // 虚函数声明
};

void Base::func() {      // 类外定义不加virtual
    // 实现
}

3.2 虚函数重写规则

  1. 函数签名必须完全相同(返回值类型、函数名、参数列表)

  2. 基类函数必须有virtual关键字

  3. 派生类virtual可省略(但不推荐)

3.3 协变(特殊情况)

cpp

复制代码
class A {};
class B : public A {};

class Base {
public:
    virtual A* create() { return new A; }
};

class Derived : public Base {
public:
    virtual B* create() override { return new B; }  // 协变:返回值类型不同
};

4. 虚函数表原理

4.1 虚函数表结构

cpp

复制代码
class Base {
public:
    virtual void func1() {}
    virtual void func2() {}
    int a;
};

int main() {
    Base b;
    cout << sizeof(b) << endl;  // 输出:8(32位)或16(64位)
    // 包含:虚表指针 + 成员变量
    return 0;
}

4.2 内存布局

text

复制代码
Base对象:
+--------------+
| vptr         | -> 指向虚函数表
+--------------+
| int a        | -> 成员变量
+--------------+

虚函数表:
+--------------+
| &Base::func1 |
+--------------+
| &Base::func2 |
+--------------+

4.3 派生类虚表

cpp

复制代码
class Derived : public Base {
public:
    virtual void func1() override {}  // 重写
    virtual void func3() {}           // 新增虚函数
};

// Derived虚表:
// 1. &Derived::func1(覆盖基类)
// 2. &Base::func2(继承)
// 3. &Derived::func3(新增)

5. 重要特例

5.1 虚析构函数

cpp

复制代码
class Base {
public:
    virtual ~Base() {  // 虚析构函数
        cout << "~Base()" << endl;
    }
};

class Derived : public Base {
public:
    ~Derived() {  // 自动成为虚函数
        cout << "~Derived()" << endl;
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;  // 正确调用~Derived()和~Base()
    return 0;
}

5.2 纯虚函数与抽象类

cpp

复制代码
class Animal {  // 抽象类
public:
    virtual void makeSound() = 0;  // 纯虚函数
    
    // 纯虚函数可以有实现(但很少用)
    virtual void sleep() = 0 { 
        cout << "Animal sleeping" << endl;
    }
};

class Dog : public Animal {
public:
    virtual void makeSound() override {
        cout << "汪汪" << endl;
    }
    
    virtual void sleep() override {
        Animal::sleep();  // 调用基类实现
        cout << "Dog dreaming" << endl;
    }
};

6. C++11新特性

6.1 override关键字

cpp

复制代码
class Base {
public:
    virtual void func(int) {}
};

class Derived : public Base {
public:
    virtual void func(int) override {}  // 正确
    // virtual void func(double) override {}  // 错误:不是重写
};

6.2 final关键字

cpp

复制代码
class Base {
public:
    virtual void func() final {}  // 禁止重写
};

class Derived : public Base {
public:
    // virtual void func() {}  // 错误:不能重写final函数
};

class Base2 final {};  // 禁止继承
// class Derived2 : public Base2 {};  // 错误

7. 重载、重写、隐藏对比

特性 重载 (Overload) 重写/覆盖 (Override) 隐藏 (Hide)
作用域 同一作用域 不同作用域(继承) 不同作用域(继承)
函数名 相同 相同 相同
参数列表 必须不同 必须相同 可以不同
返回值 可以不同 必须相同(协变除外) 可以不同
virtual 不需要 基类必须有virtual 不需要
访问权限 可以不同 可以不同 可以不同

8. 常见面试题

8.1 选择题示例

cpp

复制代码
class A {
public:
    virtual void func(int val = 1) { 
        cout << "A->" << val << endl;
    }
    virtual void test() { func(); }
};

class B : public A {
public:
    void func(int val = 0) { 
        cout << "B->" << val << endl;
    }
};

int main() {
    B* p = new B;
    p->test();  // 输出:B->1
    return 0;
}

解析 :调用test()时,this指向B对象,调用func()使用动态绑定。但默认参数使用静态绑定,所以使用A的默认值1。

8.2 内存布局题

cpp

复制代码
class Base {
public:
    virtual void f1() {}
    virtual void f2() {}
    int a;
    char b;
};

int main() {
    Base b;
    cout << sizeof(b) << endl;
    // 32位:4(vptr) + 4(int) + 1(char) + 3(对齐) = 12
    // 64位:8(vptr) + 4(int) + 1(char) + 3(对齐) = 16
    return 0;
}

8.3 多态原理题

cpp

复制代码
class Animal {
public:
    virtual void speak() const {
        cout << "Animal sound" << endl;
    }
};

class Cat : public Animal {
public:
    virtual void speak() const override {
        cout << "Meow" << endl;
    }
};

void makeSound(const Animal& animal) {
    animal.speak();  // 动态绑定
}

int main() {
    Cat cat;
    makeSound(cat);  // 输出:Meow
    return 0;
}

9. 最佳实践

9.1 何时使用多态?

  1. 需要处理多种类型对象,但有统一接口

  2. 需要在运行时决定调用哪个函数

  3. 需要扩展性,添加新类型不影响现有代码

9.2 设计建议

  1. 基类析构函数设为虚函数

  2. 使用override明确重写意图

  3. 接口类使用纯虚函数

  4. 避免在构造函数/析构函数中调用虚函数

9.3 性能考虑

  1. 虚函数调用有额外开销(虚表查找)

  2. 虚函数不能内联(通常)

  3. 虚表增加对象大小(一个指针)

10. 总结

多态是C++面向对象编程的核心特性,通过虚函数和继承实现运行时多态。理解多态需要掌握:

  1. 实现条件:虚函数 + 重写 + 基类指针/引用

  2. 底层原理:虚函数表和虚表指针

  3. 关键语法virtualoverridefinal

  4. 特殊场景:虚析构函数、纯虚函数、协变

  5. 设计原则:开闭原则、里氏替换原则

多态使得代码更加灵活、可扩展,是设计复杂系统的重要工具。正确使用多态可以提高代码的复用性和可维护性,但也需要注意性能开销和正确性问题。

相关推荐
努力学习的小廉9 分钟前
【QT(七)】—— 常用控件(四)
开发语言·qt
CoderCodingNo15 分钟前
【GESP】C++六级考试大纲知识点梳理, (3) 哈夫曼编码与格雷码
开发语言·数据结构·c++
毛毛蹭蹭15 分钟前
github copilot 0.33模型使用问题
github
介一安全16 分钟前
国内 GitHub 仓库下载提速
gitee·github
froginwe1124 分钟前
C 标准库 - `<errno.h>`
开发语言
CoderJia程序员甲26 分钟前
GitHub 热榜项目 - 日榜(2026-01-17)
ai·开源·大模型·github·ai教程
鹿角片ljp34 分钟前
Java IO流案例:使用缓冲流恢复《出师表》文章顺序
java·开发语言·windows
纵有疾風起43 分钟前
【Linux 系统开发】基础开发工具详解:自动化构建、版本控制与调试器开发实战
linux·服务器·开发语言·c++·经验分享·开源·bash
D_evil__44 分钟前
【Effective Modern C++】第一章 类型推导:3. 理解 decltype
c++
一只小bit1 小时前
Qt 文件:QFile 文件读写与管理教程
前端·c++·qt·gui