文章目录
一、虚函数(Virtual Function)
虚函数是C++中实现运行时多态(动态绑定) 的核心机制,基类中声明为virtual的成员函数,派生类可重写(override)该函数,通过基类指针/引用调用时,会根据实际指向的对象类型调用对应版本。
1. 声明规则
- 基类中使用
virtual关键字声明,语法:virtual 返回值类型 函数名(参数列表); - 虚函数必须有定义(除非是纯虚函数),可在类内或类外定义。
- 派生类重写虚函数时,
virtual关键字可省略(编译器会自动识别),但建议显式写virtual或override(C++11起)增强可读性。
2. 示例代码
cpp
#include <iostream>
using namespace std;
// 基类
class Base {
public:
// 声明虚函数(类内声明)
virtual void show(); // 仅声明,类外定义
// 类内定义的虚函数
virtual void display() {
cout << "Base::display()" << endl;
}
};
// 虚函数的类外定义(必须加类名限定,virtual关键字仅在声明时用,定义时省略)
void Base::show() {
cout << "Base::show()" << endl;
}
// 派生类
class Derived : public Base {
public:
// 重写基类虚函数(virtual可省略,建议加override)
void show() override { // override关键字:编译器检查是否真的重写了基类虚函数
cout << "Derived::show()" << endl;
}
// 重写display,省略virtual(不推荐)
void display() override {
cout << "Derived::display()" << endl;
}
};
int main() {
Base* ptr = new Derived(); // 基类指针指向派生类对象
ptr->show(); // 调用Derived::show()(动态绑定)
ptr->display(); // 调用Derived::display()(动态绑定)
delete ptr;
return 0;
}
输出结果
Derived::show()
Derived::display()
二、纯虚函数(Pure Virtual Function)
纯虚函数是没有实现 的虚函数,用于定义基类的接口,强制派生类重写该函数。包含纯虚函数的类称为抽象类,抽象类不能实例化(不能创建对象),仅能作为基类被继承。
1. 声明规则
- 语法:
virtual 返回值类型 函数名(参数列表) = 0; - 纯虚函数声明时必须加
= 0,且类内仅声明,无定义(特殊情况:纯虚函数可在类外定义,但派生类仍需重写)。 - 派生类必须重写所有纯虚函数,否则派生类也会成为抽象类,无法实例化。
2. 示例代码
cpp
#include <iostream>
using namespace std;
// 抽象类(包含纯虚函数)
class Shape {
public:
// 声明纯虚函数(无定义)
virtual double getArea() = 0;
// 纯虚函数也可以有默认实现(类外定义)
virtual void printType() = 0;
// 普通虚函数(有定义)
virtual void show() {
cout << "This is a shape." << endl;
}
};
// 纯虚函数的类外定义(可选,派生类可通过Base::func()调用)
void Shape::printType() {
cout << "Base Shape Type" << endl;
}
// 派生类:圆形
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
// 必须重写纯虚函数getArea
double getArea() override {
return 3.14159 * radius * radius;
}
// 重写纯虚函数printType(可调用基类实现)
void printType() override {
Shape::printType(); // 调用基类的默认实现
cout << "Circle Type" << endl;
}
};
// 派生类:矩形
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double getArea() override {
return width * height;
}
void printType() override {
cout << "Rectangle Type" << endl;
}
};
int main() {
// Shape s; // 错误:抽象类不能实例化
Shape* shape1 = new Circle(5.0);
Shape* shape2 = new Rectangle(4.0, 6.0);
cout << "Circle Area: " << shape1->getArea() << endl;
shape1->printType();
shape1->show(); // 调用基类的虚函数
cout << "\nRectangle Area: " << shape2->getArea() << endl;
shape2->printType();
delete shape1;
delete shape2;
return 0;
}
输出结果
Circle Area: 78.53975
Base Shape Type
Circle Type
This is a shape.
Rectangle Area: 24
Rectangle Type
三、关键区别总结
| 特性 | 虚函数 | 纯虚函数 |
|---|---|---|
| 定义要求 | 必须有定义(类内/类外) | 声明时= 0,类内无定义(可类外定义) |
| 类的性质 | 基类可实例化 | 包含纯虚函数的类为抽象类,不可实例化 |
| 派生类要求 | 可重写,也可不重写 | 必须重写,否则派生类也是抽象类 |
| 用途 | 提供默认实现,支持多态 | 定义接口,强制派生类实现具体逻辑 |
四、注意事项
- 虚函数/纯虚函数不能是
static(静态函数属于类,不属于对象,无法动态绑定)。 - 析构函数建议声明为虚函数(尤其是基类),避免派生类对象析构时内存泄漏。
- C++11起,重写虚函数时建议加
override关键字,编译器会检查重写的正确性(参数、返回值匹配)。 - 纯虚函数的类外定义仅作为"默认实现",派生类重写后仍可通过
基类::函数名()调用。