C++ 多态
什么是多态?
多 态(Polymorphism)是面向对象编程的核心概念之一,字面意思是"多种形态"。在C++中,多态允许我们使用基类指针或引用来调用派生类的函数,从而在运行时决定具体执行哪个派生类的行为。
多态提供了接口重用的能力,使我们能够编写更加灵活和可扩展的代码。
备注
多态是面向对象编程的三大特性之一,另外两个是封装和继承。多态建立在继承的基础之上。
多态的类型
在C++中,多态主要分为两种类型:
- 编译时多态(静态多态):通过函数重载和运算符重载实现
- 运行时多态(动态多态):通过虚函数和继承实现
本文将主要关注运行时多态,因为这是C++面向对象编程中更为核心的多态概念。
运行时多态的实现
虚函数
要实现运行时多态,我们需要使用虚函数。在基类中声明的虚函数可以在派生类中被重写(覆盖),当通过基类指针或引用调用这个函数时,会根据指针指向的对象类型来决定调用哪个版本的函数。
使用virtual
关键字来声明虚函数:
class Base {
public:
virtual void display() {
std::cout << "Base class display function" << std::endl;
}
};
class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};
int main() {
Base* ptr;
Derived derivedObj;
ptr = &derivedObj;
// 虽然ptr是Base类型的指针,但它指向Derived对象
// 所以这里会调用Derived类的display函数
ptr->display(); // 输出: Derived class display function
return 0;
}
输出结果:
Derived class display function
override关键字
C++11引入了override
关键字,它可以帮助我们明确标记出哪些函数是重写基类的虚函数,这样编译器可以帮我们检查是否正确重写:
class Base {
public:
virtual void show() {
std::cout << "Base::show()" << std::endl;
}
};
class Derived : public Base {
public:
// 使用override明确表示这是重写基类的虚函数
void show() override {
std::cout << "Derived::show()" << std::endl;
}
// 如果函数名拼写错误或参数不匹配,使用override会导致编译错误
// void showw() override {} // 编译错误:找不到要重写的虚函数
};
虚析构函数
当通过基类指针删除派生类对象时,如果基类的析构函数不是虚函数,则只会调用基类的析构函数,而不会调用派生类的析构函数,这可能导致内存泄漏。
因此,当类可能作为基类时,应当将其析构函数声明为虚函数:
class Base {
public:
Base() {
std::cout << "Base constructor" << std::endl;
}
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor" << std::endl;
}
~Derived() override {
std::cout << "Derived destructor" << std::endl;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // 会正确调用Derived和Base的析构函数
return 0;
}
输出结果:
Base constructor
Derived constructor
Derived destructor
Base destructor
纯虚函数和抽象类
纯虚函数
纯虚函数是一个在基类中声明但没有实现的虚函数,语法是在函数声明后加上= 0
:
virtual return_type function_name(parameters) = 0;