C++ 多态:面向对象编程中的灵活性与扩展性
什么是多态?
多态(Polymorphism)是面向对象编程中的一个重要概念,它允许对象在不同的情况下表现出不同的行为。在 C++ 中,多态性可以分为两类:编译时多态和运行时多态。
-
编译时多态:在编译期间就能够决定调用哪个函数。常见的编译时多态包括函数重载和运算符重载。
-
运行时多态:在运行期间决定调用哪个函数,通常是通过继承和虚函数实现的。这是 C++ 中常见的多态形式,也是面向对象编程中最常用的多态。
运行时多态:通过虚函数实现
运行时多态的关键是虚函数(virtual
)。当我们通过基类指针或引用调用派生类的函数时,C++ 会根据对象的实际类型来调用正确的函数,而不是静态地绑定到基类的函数。
1. 基本的多态示例
#include <iostream>
using namespace std;// 基类
class Shape {
public:// 虚函数,允许派生类重写virtual void draw() const {cout << "Drawing a shape" << endl;}
};// 派生类1:Circle
class Circle : public Shape {
public:void draw() const override {cout << "Drawing a Circle" << endl;}
};// 派生类2:Square
class Square : public Shape {
public:void draw() const override {cout << "Drawing a Square" << endl;}
};int main() {Shape* shape;Circle circle;Square square;// 使用基类指针指向派生类对象shape = &circle;shape->draw(); // 输出: Drawing a Circleshape = □shape->draw(); // 输出: Drawing a Squarereturn 0;
}
解释:
-
Shape
类是基类,其中有一个虚函数draw()
,表示画图的行为。 -
Circle
和Square
类继承自Shape
类,并重写了draw()
函数。 -
在
main()
函数中,我们通过基类指针shape
来指向不同的派生类对象(circle
和square
)。由于draw()
是虚函数,C++ 会在运行时根据对象的实际类型来调用相应的函数。
输出:
Drawing a Circle
Drawing a Square
虚函数与构造函数
虚函数是动态绑定的,但构造函数不是。也就是说,当我们通过基类指针创建对象时,虚函数表会指向基类的虚函数,即使派生类已经重写了该函数。构造函数执行时,只有基类的构造函数会被调用。
示例:虚函数与构造函数
#include <iostream>
using namespace std;class Base {
public:Base() {cout << "Base class constructor called" << endl;}virtual void display() const {cout << "Base class display function" << endl;}
};class Derived : public Base {
public:Derived() {cout << "Derived class constructor called" << endl;}void display() const override {cout << "Derived class display function" << endl;}
};int main() {Derived obj;obj.display(); // 输出: Derived class display functionreturn 0;
}
输出:
Base class constructor called
Derived class constructor called
Derived class display function
解释:
-
即使我们在派生类
Derived
中重写了display()
函数,基类的构造函数会先被调用,这是因为对象是先构造基类部分,再构造派生类部分。 -
然而,
display()
是一个虚函数,它会根据对象的实际类型(Derived
类)来调用派生类的版本。
虚析构函数
为了确保当我们通过基类指针删除派生类对象时,派生类的析构函数能够正确执行,我们需要将基类的析构函数声明为虚函数。
示例:虚析构函数
#include <iostream>
using namespace std;class Base {
public:virtual ~Base() {cout << "Base class destructor called" << endl;}
};class Derived : public Base {
public:~Derived() {cout << "Derived class destructor called" << endl;}
};int main() {Base* ptr = new Derived();delete ptr; // 输出: Derived class destructor called// Base class destructor calledreturn 0;
}
输出:
Derived class destructor called
Base class destructor called
解释:
-
如果我们没有将
Base
类的析构函数声明为虚函数,调用delete ptr
时,只会调用基类的析构函数,导致派生类的析构函数没有被调用,这可能导致资源泄漏。 -
通过将析构函数声明为虚函数,C++ 会确保在删除基类指针时,首先调用派生类的析构函数,然后调用基类的析构函数。
总结
-
多态是 C++ 面向对象编程的重要特性,通过继承和虚函数实现,可以使得不同的派生类对象能够在运行时表现出不同的行为。
-
虚函数是实现运行时多态的关键,允许派生类重写基类的函数,并在运行时通过基类指针或引用调用派生类的函数。
-
虚析构函数可以保证通过基类指针删除派生类对象时,析构函数能够正确调用,避免资源泄漏。
多态为程序提供了极大的灵活性和扩展性,能够简化代码结构并提高代码的可维护性。