不同类的对象对相同的方法或函数产生有不同的反应。多态的实现依赖于虚函数
静态多态和动态多态
静态多态(编译时多态)
动态多态(运行时多态)
虚函数是指使用了修饰符virtua修饰过后的函数,而且定义虚函数的函数必须为类的成员函数,虚函数被继承后所继承的派生类都是为虚函数,析构函数可以定义为虚函数,但是构造函数(与友员函数)却不能定义为虚函数。
虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在派生类中对积累定义的虚函数进行重写时,需要在派生类中声明该方法为虚方法。
当使用多态特性,让基类指针指向派生类对象时,如果析构函数不是虚函数,通过基类指针销毁派生类对象时,会调用静态绑定的析构函数,也就是基类的析构函数,从而只能销毁属于基类的元素,导致派生类析构不完全,程序就会出现资源泄露或未定义行为。
在C++中,构造函数(包括拷贝构造函数和移动构造函数)不能声明为虚函数。虚函数在运行时通过对象的虚函数表(vtable)来调用,而构造函数在对象被创建之前执行,因此在对象存在之前虚函数表也不存在,无法实现虚函数的多态性。
纯虚函数必须在基类中定义,没有具体的实现代码,只有函数声明。它规定派生类必须提供该函数的具体实现。 注意:纯虚函数的类无法被实例化,只能作为基类来派生其他类。派生类必须提供对应的纯虚函数的具体实现。
示例(定义纯虚函数的语法是在函数声明后面加上 = 0
):
class AbstractBase {
public:
virtual void pureVirtualFunction1() = 0; // 第一个纯虚函数
virtual void pureVirtualFunction2(int x) = 0; // 第二个纯虚函数带参数
virtual void pureVirtualFunction3(double y, const std::string& str) = 0; // 第三个纯虚函数带多个参数
};
};
class Derived : public AbstractBase {
public:
void pureVirtualFunction1() override { //override表明重写虚函数,可不加
// 提供具体的实现
// ...
}
void pureVirtualFunction2(int x) override {
// 提供具体的实现
// ...
}
void pureVirtualFunction3(double y, const std::string& str) override {
// 提供具体的实现
// ...
}
};
虚函数的定义在类的定义中,而不是在创建对象时出现。
#include <iostream>
using namespace std;
class Shape {
public:
virtual double area() const = 0; // 纯虚函数
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const {
return 3.14159265359 * radius * radius;
}
};
class Rectangle : public Shape {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const {
return width * height;
}
};
int main() {
Circle circle(5.0);
Rectangle rectangle(4.0, 6.0);
Shape* shape1 = &circle;
Shape* shape2 = &rectangle;
std::cout << "面积1: " << shape1->area() << std::endl;
std::cout << "面积2: " << shape2->area() << std::endl;
return 0;
}
非知之难,行之为难;非行之难,终之斯难