【C++重载操作符与转换】纯虚函数
目录
一、纯虚函数的基本概念
1.1 定义与语法
1.2 抽象类
1.3 派生类的实现要求
二、纯虚函数的使用场景
2.1 定义接口
2.2 实现多态
2.3 设计框架
三、纯虚函数的特性
3.1 纯虚函数可以有实现
3.2 抽象类的构造函数和析构函数
3.3 纯虚函数与接口继承
四、纯虚函数与普通虚函数的对比
五、纯虚函数的应用实例
5.1 图形库设计
5.2 游戏角色系统
5.3 工厂模式实现
六、纯虚函数的注意事项
6.1 避免在构造函数和析构函数中调用纯虚函数
6.2 纯虚函数与默认参数
6.3 纯虚函数与多重继承
七、总结
在 C++ 面向对象编程中,纯虚函数(Pure Virtual Function)是一个核心概念。它允许我们定义一个接口,而不需要实现具体的功能,从而实现多态性。
一、纯虚函数的基本概念
1.1 定义与语法
纯虚函数是在基类中声明的虚函数,它在基类中没有具体实现,而是要求任何派生类都必须提供自己的实现。纯虚函数的声明语法是在函数原型后加= 0
。
class Shape {
public:// 纯虚函数virtual double area() const = 0;
};
1.2 抽象类
包含至少一个纯虚函数的类称为抽象类(Abstract Class)。抽象类不能实例化,只能作为基类被继承。
// 错误:无法实例化抽象类
// Shape s; // 编译错误// 正确:可以定义抽象类的指针或引用
Shape* ptr;
1.3 派生类的实现要求
任何继承抽象类的派生类必须实现所有纯虚函数,否则派生类也会被视为抽象类。
class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}// 实现纯虚函数double area() const override {return 3.14 * radius * radius;}
};
二、纯虚函数的使用场景
2.1 定义接口
纯虚函数最常见的用途是定义接口,强制派生类实现特定的功能。
class Drawable {
public:virtual void draw() const = 0;virtual ~Drawable() {}
};class Rectangle : public Drawable {
public:void draw() const override {std::cout << "Drawing a rectangle." << std::endl;}
};
2.2 实现多态
通过纯虚函数,可以实现运行时多态,使基类指针能够根据实际对象类型调用相应的函数。
void render(const Drawable& obj) {obj.draw();
}int main() {Rectangle rect;render(rect); // 输出: Drawing a rectangle.
}
2.3 设计框架
在框架设计中,纯虚函数可以定义框架的扩展点,允许用户通过继承实现自定义功能。
class Application {
public:virtual void initialize() = 0;virtual void run() = 0;virtual void shutdown() = 0;void execute() {initialize();run();shutdown();}
};
三、纯虚函数的特性
3.1 纯虚函数可以有实现
虽然纯虚函数在基类中没有声明体,但可以为其提供定义。不过,派生类仍需提供自己的实现。
class Base {
public:virtual void func() = 0; // 纯虚函数声明
};// 纯虚函数的定义
void Base::func() {std::cout << "Base::func() implementation" << std::endl;
}class Derived : public Base {
public:void func() override {std::cout << "Derived::func() implementation" << std::endl;Base::func(); // 可以调用基类的实现}
};
3.2 抽象类的构造函数和析构函数
抽象类可以有构造函数和析构函数。构造函数用于初始化抽象类的成员,析构函数通常声明为虚函数,以确保正确释放派生类对象。
class Base {
protected:int value;
public:Base(int v) : value(v) {}virtual ~Base() {}virtual void print() const = 0;
};class Derived : public Base {
public:Derived(int v) : Base(v) {}void print() const override {std::cout << "Value: " << value << std::endl;}
};
3.3 纯虚函数与接口继承
纯虚函数实现了接口继承(Inheritance of Interface),而不是实现继承(Inheritance of Implementation)。派生类只继承函数的接口,而不继承实现。
四、纯虚函数与普通虚函数的对比
特性 | 纯虚函数 | 普通虚函数 |
---|---|---|
声明语法 | virtual void func() = 0; | virtual void func(); |
是否必须在基类实现 | 否 | 是 |
能否实例化包含它的类 | 否(抽象类) | 是(具体类) |
派生类是否必须实现 | 是 | 否(可继承基类实现) |
典型用途 | 定义接口 | 实现多态行为 |
五、纯虚函数的应用实例
5.1 图形库设计
设计一个图形库,使用纯虚函数定义各种图形的公共接口。
#include <iostream>
#include <vector>class Shape {
public:virtual double area() const = 0;virtual void draw() const = 0;virtual ~Shape() {}
};class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() const override {return 3.14 * radius * radius;}void draw() const override {std::cout << "Drawing a circle with radius " << radius << std::endl;}
};class Rectangle : public Shape {
private:double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}double area() const override {return width * height;}void draw() const override {std::cout << "Drawing a rectangle with width " << width<< " and height " << height << std::endl;}
};int main() {std::vector<Shape*> shapes;shapes.push_back(new Circle(5.0));shapes.push_back(new Rectangle(4.0, 6.0));for (const auto& shape : shapes) {std::cout << "Area: " << shape->area() << std::endl;shape->draw();delete shape;}return 0;
}
5.2 游戏角色系统
设计一个游戏角色系统,使用纯虚函数定义角色的行为。
#include <iostream>class Character {
public:virtual void attack() = 0;virtual void defend() = 0;virtual ~Character() {}
};class Warrior : public Character {
public:void attack() override {std::cout << "Warrior uses sword!" << std::endl;}void defend() override {std::cout << "Warrior uses shield!" << std::endl;}
};class Mage : public Character {
public:void attack() override {std::cout << "Mage casts fireball!" << std::endl;}void defend() override {std::cout << "Mage uses magic barrier!" << std::endl;}
};void simulateBattle(Character& attacker, Character& defender) {attacker.attack();defender.defend();
}int main() {Warrior warrior;Mage mage;simulateBattle(warrior, mage);simulateBattle(mage, warrior);return 0;
}
5.3 工厂模式实现
使用纯虚函数实现工厂模式,创建不同类型的产品。
#include <iostream>
#include <string>// 产品接口
class Product {
public:virtual void use() = 0;virtual ~Product() {}
};// 具体产品
class ConcreteProductA : public Product {
public:void use() override {std::cout << "Using Product A" << std::endl;}
};class ConcreteProductB : public Product {
public:void use() override {std::cout << "Using Product B" << std::endl;}
};// 工厂接口
class Factory {
public:virtual Product* createProduct() = 0;virtual ~Factory() {}
};// 具体工厂
class ConcreteFactoryA : public Factory {
public:Product* createProduct() override {return new ConcreteProductA();}
};class ConcreteFactoryB : public Factory {
public:Product* createProduct() override {return new ConcreteProductB();}
};int main() {Factory* factoryA = new ConcreteFactoryA();Product* productA = factoryA->createProduct();productA->use();Factory* factoryB = new ConcreteFactoryB();Product* productB = factoryB->createProduct();productB->use();delete productA;delete factoryA;delete productB;delete factoryB;return 0;
}
六、纯虚函数的注意事项
6.1 避免在构造函数和析构函数中调用纯虚函数
在基类的构造函数或析构函数中调用纯虚函数是不安全的,因为此时派生类部分可能尚未完全构造或已被销毁。
6.2 纯虚函数与默认参数
纯虚函数可以有默认参数,但调用时使用的参数值由调用点的静态类型决定,而非动态类型。
class Base {
public:virtual void func(int x = 10) = 0;
};class Derived : public Base {
public:void func(int x = 20) override {std::cout << "x = " << x << std::endl;}
};int main() {Base* ptr = new Derived();ptr->func(); // 输出 x = 10,使用基类的默认参数delete ptr;return 0;
}
6.3 纯虚函数与多重继承
在多重继承中,一个类可以从多个抽象类继承纯虚函数,必须实现所有纯虚函数才能成为具体类。
七、总结
纯虚函数是 C++ 面向对象编程中的重要工具,它允许我们定义抽象接口,实现多态性,并强制派生类提供特定功能的实现。通过合理使用纯虚函数,可以设计出灵活、可扩展的类层次结构。