C++中的多态(Polymorphism)是面向对象编程的三大特性之一,它允许使用父类类型的指针或引用来指向子类对象,并通过该指针或引用来调用子类中覆盖或重载的方法,从而实现一种通用的、可重用的程序设计。
多态的实现主要依赖于以下机制:
- 虚函数(Virtual Functions):
- 父类中声明为
virtual
的成员函数可以在子类中被覆盖(override)。 - 当使用父类类型的指针或引用来指向子类对象时,通过该指针或引用来调用虚函数,会执行子类中覆盖的版本,而不是父类中的版本。
- 父类中声明为
- 纯虚函数(Pure Virtual Functions):
- 在虚函数的声明后加上
= 0
,则该函数变为纯虚函数。 - 包含纯虚函数的类被称为抽象类(Abstract Class),它不能被实例化。
- 派生自抽象类的子类必须提供纯虚函数的实现,除非该子类也是抽象类。
- 在虚函数的声明后加上
- 动态绑定(Dynamic Binding):
- 也称为后期绑定或运行时绑定。
- 在运行时,根据对象的实际类型来确定调用哪个版本的成员函数。
- 函数重载(Function Overloading):
- 虽然函数重载与多态的概念不完全相同,但它是多态的一种表现形式。
- 同一个类中可以存在多个同名但参数列表不同的成员函数,编译器根据调用时提供的参数来确定调用哪个版本的函数。
- 构造函数和析构函数不能是虚函数:
- 构造函数在对象被创建时调用,而析构函数在对象被销毁时调用。在这两个时间点,对象的类型已经确定,因此没有必要进行动态绑定。
- 如果需要在析构时执行特定的操作,可以考虑将这部分操作放在一个虚函数中,并在析构函数中调用它。
- 多态与继承、封装的关系:
- 多态性是与继承紧密相关的,它是通过类的继承层次结构来实现的。
- 封装则是将对象的属性和操作隐藏起来,只对外提供必要的接口。多态性可以看作是封装的一种延续,它使得我们可以使用统一的接口来处理不同的对象。
示例:
cpp复制代码
class Animal { | |
public: | |
virtual void speak() { | |
std::cout << "The animal speaks" << std::endl; | |
} | |
virtual ~Animal() {} // 虚析构函数,确保多态删除时正确调用子类的析构函数 | |
}; | |
class Dog : public Animal { | |
public: | |
void speak() override { | |
std::cout << "The dog barks" << std::endl; | |
} | |
}; | |
class Cat : public Animal { | |
public: | |
void speak() override { | |
std::cout << "The cat meows" << std::endl; | |
} | |
}; | |
void letAnimalSpeak(Animal* animal) { | |
animal->speak(); // 多态调用,执行的是实际对象(Dog或Cat)的speak方法 | |
} | |
int main() { | |
Dog myDog; | |
Cat myCat; | |
letAnimalSpeak(&myDog); // 输出 "The dog barks" | |
letAnimalSpeak(&myCat); // 输出 "The cat meows" | |
return 0; | |
} |