在C++编程领域中,多态是一个极为重要的概念。若想深入学习C++多态,首先需明晰“多态”一词在C++中的确切含义。简单来讲,多态旨在运用统一不变的代码或函数,来达成多样不同的算法,其实现形式涵盖了重载、模板以及虚函数等。
多态主要分为静态多态与动态多态这两大类别。静态多态,指的是在编译阶段便已确定的相关内容,典型的如函数的重载。而动态多态,则是在程序运行时才能确定的情况,虚函数便是其主要实现方式。
接下来,将竭尽全力,力求详细阐释C++多态,以期抛砖引玉,助力刚踏入C++大家庭的同学们有所收获。
静态多态
静态多态,即在编译阶段就已然确定下来的内容,像函数的重载就属于此类。相较于动态多态,它相对容易理解。尽管重载这一概念本身并不复杂,但考虑到刚入门的同学可能对此尚未完全掌握,为全面阐述对多态的理解,这里仍对其进行简要介绍。
谈及重载,需满足以下几个关键条件:
- 首要条件是两个函数的作用域必须一致。这一点尤为关键,因为基类与派生类处于不同作用域,所以基类和派生类的函数无法构成重载关系。
- 函数名称必须相同。
- 参数列表,包括参数类型、参数个数以及参数顺序,必须存在差异。
- 特别要注意的是,函数重载与返回值类型并无关联。只要满足上述前三个条件,即可称之为函数重载。
例如:
// 重载函数示例
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
在上述代码中,三个 add
函数名称相同,但参数列表各不相同,这就是典型的函数重载。在编译阶段,编译器会依据调用时传入的参数类型和个数,精准确定调用的是哪一个 add
函数。
动态多态
动态多态,是指在程序运行时才能确定具体行为的情况,其主要通过虚函数来实现。当存在继承关系时,在基类中使用 virtual
关键字声明的函数,在派生类中重新定义(函数名、参数列表、返回值类型完全相同),便构成了虚函数重写。此时,通过基类指针或引用调用该函数时,会根据指针或引用实际指向的对象类型(是基类对象还是派生类对象),在运行时动态决定调用哪个类中的虚函数版本。
例如:
class Animal {
public:
virtual void speak() {
std::cout << "Animal speaks" << std::endl;
}
};
class Dog : public Animal {
public:
void speak() override {
std::cout << "Dog barks" << std::endl;
}
};
class Cat : public Animal {
public:
void speak() override {
std::cout << "Cat meows" << std::endl;
}
};
在上述代码中,Animal
类中的 speak
函数被声明为虚函数,Dog
类和 Cat
类都重写了 speak
函数。当通过 Animal
类的指针或引用调用 speak
函数时:
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->speak(); // 运行时调用 Dog::speak()
animal2->speak(); // 运行时调用 Cat::speak()
delete animal1;
delete animal2;
return 0;
}
在 main
函数中,虽然 animal1
和 animal2
都是 Animal
类型的指针,但它们实际指向的是不同派生类的对象。在运行时,根据对象的实际类型,分别调用了 Dog
类和 Cat
类中的 speak
函数,这便是动态多态的体现。动态多态使得程序在运行时能够根据实际对象的类型,灵活地调用合适的函数,极大地增强了程序的扩展性和灵活性。