当前位置: 首页 > java >正文

【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++ 面向对象编程中的重要工具,它允许我们定义抽象接口,实现多态性,并强制派生类提供特定功能的实现。通过合理使用纯虚函数,可以设计出灵活、可扩展的类层次结构。


http://www.xdnf.cn/news/6169.html

相关文章:

  • 尚硅谷阳哥JVM
  • 智能工具协同赋能STEM教育科研|探索LLM大语言模型和数学软件Maple的创新实践
  • 2025年城市建设与交通运输国际会议(ICUCT 2025)
  • Baklib全场景知识中台驱动效能跃升
  • less中使用 @supports
  • 在C++中进行套接字编程时,主要使用以下头文件
  • CSS:选择器的优先级
  • 深入剖析某App视频详情逆向:聚焦sig3参数攻克
  • (10天冲刺版)软考:软件设计师 真题资料分享
  • Java高频面试之并发编程-17
  • 高海拔和远距离的人员识别:面部、体型和步态的融合
  • spark的Standalone模式介绍
  • 最大公约数JAVA
  • CK-S654-PA60一拖四分体式半导体电子货架专用RFID读写器|读码器接线使用说明
  • <论文>(微软)避免推荐域外物品:基于LLM的受限生成式推荐
  • “天神之眼”计算平台的算力设计(预计500-1000 TOPS)
  • 认识Docker/安装Docker
  • C及C++的SOAP协议库
  • 相关行业发展趋势写一个爬虫程序
  • 力扣3337. 字符串转换后的长度 II随笔
  • 2024年全国青少年信息素养大赛-算法创意实践C++ 华中赛区(初赛)历年真题
  • HTML5 浮动(Float)详解
  • 上海OA系统哪家好?厂商有哪些?
  • 如何在终端/命令行中把PDF的每一页转换成图片(PNG)
  • 从0开始学linux韦东山教程第三章问题小结(4)
  • 易学探索助手-个人记录(十)
  • redis 缓存穿透,缓存击穿,缓存雪崩
  • VCS X-PROP建模以及在方针中的应用
  • 利用vba替换word中多个表格,相邻单元格的文字
  • 用Array.from实现创建一个1-100的数组