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

C++ 1.面向对象编程(OOP)框架

目录

面向对象编程(OOP)框架

问题背景

OOP框架开发的关键问题解析

步骤1:抽象设计阶段

步骤2:继承层次设计

步骤3:多态机制应用

步骤4:对象关系管理

这个案例展现的核心OOP价值

封装的价值

继承的价值

多态的价值

实际开发中的应用场景

GUI框架开发

游戏开发

文件系统

扩展:现在C++ VS C++98:

内存管理差异

循环语法差异

函数对象vs Lambda

扩展:多态语法详细解析

核心多态语法要素

智能指针容器

Lambda表达式

多态调用机制

多态的工作原理

dynamic_cast安全转换


面向对象编程(OOP)框架

封装: 将数据(属性)和操作这些数据的函数(方法)捆绑在一个单元(类)内部。同时,对内部实现的细节进行隐藏,只暴露有限的、必要的接口(方法)与外部进行交互。

继承允许基于一个现有的类(父类/超类/基类)定义一个新的类(子类/派生类)。子类自动获得父类的属性和方法(除了private的,通常需要通过protected或公共方法访问),并可以添加自己特有的属性和方法,或者重写父类已有的方法以满足特定需求。

多态:字面意思是“多种形态”。在 OOP 中,指同一个接口(或父类型的引用) 可以使用不同的底层实现方式(子类的具体方法)。更具体地说,它允许你将子类对象视为父类对象(向上转型),当通过父类的引用调用一个被重写的方法时,实际执行的是子类版本的那个方法。

我将通过一个完整的案例来演示面向对象编程框架的逐步开发过程。让我们以图书管理系统为例,这个案例能很好地展现OOP的核心概念和问题解决思路。

问题背景

我们需要开发一个图书管理系统,管理不同类型的图书(普通书籍、期刊、电子书),处理借阅、归还、查询等操作。这个案例展现了以下OOP核心问题:

  • 如何抽象现实世界的概念

  • 如何处理相似但不同的对象类型

  • 如何实现代码复用和扩展性

  • 如何管理对象之间的关系

案例:

// library_project.cpp :
// 时间:2025.7.28#include <iostream>
#include <iomanip> 
#include <string.h>
#include <vector>
// ==============================================
// 步骤1: 数据抽象 - 解决"什么是对象"的问题
// ==============================================// 问题:现实中的图书有哪些共同属性和行为?
// 解决:创建抽象基类定义通用接口class Book {
protected:// 封装:将数据成员设为protected,允许子类访问但外部不能直接访问std::string isbn;    // 书籍编号std::string title;  //  书名std::string author; //  作者double price;       //  价格bool isAvailable;   //  是否可以借用public:// 构造函数:对象创建时的初始化,使用初始化列表提高效率,避免先构造再赋值// 1.有参构造,没有设计无参数构造  确保构造函数接受4个参数:isbn, title, author, priceBook(const std::string& isbn, const std::string& title,const std::string& author, double& price):isbn(isbn), title(title), author(author), price(price), isAvailable(true){std::cout << "创建图书:" << std::endl;}// 虚析构函数:确保派生类对象能正确析构// 问题:如果基类析构函数不是虚函数,通过基类指针删除派生类对象会有问题virtual ~Book() {std::cout << "销毁图书: " << title << std::endl;}// 纯虚函数:定义接口,子类必须实现// 问题:不同类型的书籍展示信息的方式可能不同virtual void displayInfo() const = 0;// 虚函数:提供默认实现,子类可以重写// 问题:不同类型书籍的借阅规则可能不同(可借不可借阅)virtual bool canBorrow() const {return isAvailable;}// 虚函数:计算借阅费用,不同类型可能有不同计费方式virtual double calculateFee(int days) const{return 0.0; // 默认免费}// 重要:添加虚函数borrow(),这样派生类才能重写它virtual void borrow(){if (canBorrow()){isAvailable = false;std::cout << "<<"<<title<<">>" << "已经被借阅出去" << std::endl;}else{std::cout << "<<" << title << ">>" << "不可借阅" << std::endl;}}void returnBook(){isAvailable = true;std::cout << "<<" << title << ">>" << "已归还" << std::endl;}std::string getIsbn(){return isbn;}std::string getTitle(){return title;}std::string getAuthor(){return author;}double getPrice(){return price;}bool getAvailability(){return isAvailable;}
};// ==============================================
// 步骤2: 继承 - 解决"代码复用"的问题
// ==============================================// 问题:普通图书、期刊、电子书都是书,但有各自特点
// 解决:通过继承复用基类代码,通过重写体现差异// 普通图书类
class PhysicalBook :public Book {
private:std::string location; // 存放位置int pages; // 页数public:// 构造函数:调用基类构造函数初始化公共属性// 正确调用基类构造函数(4个参数)PhysicalBook(const std::string& isbn, const std::string& title,const std::string& author, double price,const std::string& location, int pages): Book(isbn, title, author, price),  // 传递4个参数给基类location(location), pages(pages) {std::cout << "创建实体书,位置: " << location << std::endl;}// 重写纯虚函数:实现具体的显示逻辑void displayInfo() const override{std::cout << "=== 实体图书信息 ===" << std::endl;std::cout << "ISBN: " << isbn << std::endl;std::cout << "书名: " << title << std::endl;std::cout << "作者: " << author << std::endl;std::cout << "价格: " << std::fixed << std::setprecision(2) << price << std::endl;std::cout << "存放位置: " << location << std::endl;std::cout << "页数: " << pages << std::endl;std::cout << "状态: " << (isAvailable ? "可借" : "已借出") << std::endl;}// 重写虚函数:实体书可能有借阅费double calculateFee(int days) const override{if (days > 30){return (days - 30) * 0.5; // 超过30天后的每天按照0.5元计算}return 0.0;}// 子类特有方法std::string getLocation() const{return location;}int getPages() const{return pages;}
};// 期刊类
class Magazine : public Book {
private:int issueNumber;        // 期号std::string publishDate; // 出版日期public:Magazine(const std::string& isbn, const std::string& title,const std::string& author, double price,int issueNumber, const std::string& publishDate): Book(isbn, title, author, price), issueNumber(issueNumber), publishDate(publishDate) {}void displayInfo() const override {std::cout << "=== 期刊信息 ===" << std::endl;std::cout << "ISBN: " << isbn << std::endl;std::cout << "期刊名: " << title << std::endl;std::cout << "主编: " << author << std::endl;std::cout << "价格: " << std::fixed << std::setprecision(2) << price << std::endl;std::cout << "期号: " << issueNumber << std::endl;std::cout << "出版日期: " << publishDate << std::endl;std::cout << "状态: " << (isAvailable ? "可借" : "已借出") << std::endl;}// 期刊通常不能长期借阅bool canBorrow() const override {return isAvailable;  // 可以添加额外的期刊借阅规则}double calculateFee(int days) const override {if (days > 7) {return (days - 7) * 1.0;  // 期刊超过7天每天1元}return 0.0;}
};// 电子书类
class EBook : public Book {
private:std::string format;      // 文件格式double fileSize;         // 文件大小(MB)std::string downloadUrl; // 下载链接public:EBook(const std::string& isbn, const std::string& title,const std::string& author, double price,const std::string& format, double fileSize, const std::string& downloadUrl): Book(isbn, title, author, price), format(format), fileSize(fileSize), downloadUrl(downloadUrl) {}void displayInfo() const override {std::cout << "=== 电子书信息 ===" << std::endl;std::cout << "ISBN: " << isbn << std::endl;std::cout << "书名: " << title << std::endl;std::cout << "作者: " << author << std::endl;std::cout << "价格: " << std::fixed << std::setprecision(2) << price << std::endl;std::cout << "格式: " << format << std::endl;std::cout << "文件大小: " << fileSize << "MB" << std::endl;std::cout << "下载地址: " << downloadUrl << std::endl;std::cout << "状态: " << (isAvailable ? "可下载" : "暂不可用") << std::endl;}// 电子书借阅逻辑不同:可以同时被多人"借阅"bool canBorrow() const override {return true;  // 电子书总是可以借阅}void borrow() override {std::cout << "正在下载电子书: " << title << std::endl;std::cout << "下载链接: " << downloadUrl << std::endl;// 注意:电子书不改变isAvailable状态}// 电子书特有方法void download() const {std::cout << "开始下载 " << "<<" << title << ">>" << " (" << format << ", " << fileSize << "MB)" << std::endl;}
};// ==============================================
// 步骤3: 多态 - 解决"统一接口处理不同对象"的问题
// ==============================================// 问题:如何用统一的方式处理不同类型的书籍?
// 解决:通过多态,使用基类指针或引用调用派生类的重写方法class LibraryManager
{
private:// 使用智能指针管理书籍对象,自动内存管理std::vector<std::unique_ptr<Book>> books;
public:void addBook(std::unique_ptr<Book> book){books.push_back(std::move(book));std::cout << "书籍已添加到图书馆" << std::endl;}// 显示所有书籍:多态调用每个对象的displayInfo方法void displayAllBooks() const{std::cout << "\n========== 图书馆藏书 ==========" << std::endl;for (const auto& book : books) {book->displayInfo();  // 多态调用:运行时决定调用哪个版本std::cout << std::endl;}}// 按ISBN查找书籍Book* findBookByIsbn(const std::string & isbn) {// 使用STL算法和lambda表达式auto it = std::find_if(books.begin(), books.end(),[&isbn](const std::unique_ptr<Book>& book) {return book->getIsbn() == isbn;});return (it != books.end()) ? it->get() : nullptr;}// 借阅书籍:统一接口处理不同类型bool borrowBook(const std::string& isbn) {Book* book = findBookByIsbn(isbn);if (book && book->canBorrow()) {book->borrow();  // 多态调用return true;}std::cout << "无法借阅书籍 ISBN: " << isbn << std::endl;return false;}// 归还书籍bool returnBook(const std::string& isbn) {Book* book = findBookByIsbn(isbn);if (book) {book->returnBook();return true;}std::cout << "未找到书籍 ISBN: " << isbn << std::endl;return false;}// 计算所有已借书籍的费用void calculateAllFees(int days) const {std::cout << "\n========== 借阅费用计算 ==========" << std::endl;double totalFee = 0.0;for (const auto& book : books) {if (!book->getAvailability()) {  // 已借出的书double fee = book->calculateFee(days);  // 多态调用std::cout << book->getTitle() << ": ¥"<< std::fixed << std::setprecision(2) << fee << std::endl;totalFee += fee;}}std::cout << "总费用: " << std::fixed << std::setprecision(2) << totalFee << std::endl;}// 统计不同类型书籍数量void showStatistics() const {int physicalCount = 0, magazineCount = 0, ebookCount = 0;for (const auto& book : books) {// 使用dynamic_cast进行安全的向下转型if (dynamic_cast<PhysicalBook*>(book.get())) {physicalCount++;}else if (dynamic_cast<Magazine*>(book.get())) {magazineCount++;}else if (dynamic_cast<EBook*>(book.get())) {ebookCount++;}}std::cout << "\n========== 图书馆统计 ==========" << std::endl;std::cout << "实体图书: " << physicalCount << " 本" << std::endl;std::cout << "期刊: " << magazineCount << " 本" << std::endl;std::cout << "电子书: " << ebookCount << " 本" << std::endl;std::cout << "总计: " << books.size() << " 本" << std::endl;}
};// ==============================================
// 步骤4: 组合和关联 - 解决"对象间关系"的问题
// ==============================================// 问题:用户和图书之间的借阅关系如何建模?
// 解决:通过组合关系管理用户的借阅记录class User
{
private:std::string userId;std::string name;std::vector<std::string> borrowedBooks; // 存储借阅的书籍的ISBN
public:User(const std::string& userId,const std::string &name):userId(userId),name(name){}void borrowBook(const std::string& isbn) {borrowedBooks.push_back(isbn);}void returnBook(const std::string& isbn) {auto it = std::find(borrowedBooks.begin(), borrowedBooks.end(), isbn);if (it != borrowedBooks.end()) {borrowedBooks.erase(it);}}void showBorrowedBooks() const {std::cout << "\n用户 " << name << " 的借阅记录:" << std::endl;if (borrowedBooks.empty()) {std::cout << "暂无借阅记录" << std::endl;}else {for (const auto& isbn : borrowedBooks) {std::cout << "- ISBN: " << isbn << std::endl;}}}std::string getUserId() const { return userId; }std::string getName() const { return name; }int getBorrowedCount() const { return borrowedBooks.size(); }};// ==============================================
// 主函数:演示OOP框架的完整使用
// ==============================================int main()
{std::cout << "========== OOP图书管理系统演示 ==========" << std::endl;// 创建图书馆管理器LibraryManager library;std::cout << "\n--- 步骤1: 创建不同类型的书籍 ---" << std::endl;// 使用make_unique创建智能指针,自动内存管理library.addBook(std::make_unique<PhysicalBook>("978-0201633610", "设计模式", "Gang of Four", 89.90, "A区-3层", 395));library.addBook(std::make_unique<Magazine>("ISSN-1234-5678", "程序员杂志", "编辑部", 25.00, 202401, "2024-01-15"));library.addBook(std::make_unique<EBook>("978-1449355739", "JavaScript权威指南", "David Flanagan", 119.00,"PDF", 15.2, "https://example.com/download/js-guide"));std::cout << "\n--- 步骤2: 多态展示所有书籍信息 ---" << std::endl;library.displayAllBooks();std::cout << "\n--- 步骤3: 统计信息展示 ---" << std::endl;library.showStatistics();std::cout << "\n--- 步骤4: 借阅操作演示 ---" << std::endl;library.borrowBook("978-0201633610");  // 借实体书library.borrowBook("ISSN-1234-5678");  // 借期刊library.borrowBook("978-1449355739");  // 借电子书std::cout << "\n--- 步骤5: 费用计算演示 ---" << std::endl;library.calculateAllFees(45);  // 计算借阅45天的费用std::cout << "\n--- 步骤5: 费用计算演示 ---" << std::endl;library.calculateAllFees(45);  // 计算借阅45天的费用std::cout << "\n--- 步骤6: 归还操作演示 ---" << std::endl;library.returnBook("978-0201633610");std::cout << "\n--- 步骤7: 用户管理演示 ---" << std::endl;User user1("U001", "张三");user1.borrowBook("978-0201633610");user1.borrowBook("ISSN-1234-5678");user1.showBorrowedBooks();std::cout << "\n========== 演示结束 ==========" << std::endl;return 0;
}/*
OOP解决的核心问题总结:1. 抽象问题:如何将现实世界的概念转化为程序对象- 通过类定义对象的属性和行为- 通过抽象基类定义通用接口2. 复用问题:如何避免重复代码- 通过继承复用基类的代码- 通过虚函数实现接口的不同实现3. 扩展问题:如何在不修改现有代码的情况下添加新功能- 通过多态支持新的派生类- 通过虚函数机制支持功能扩展4. 维护问题:如何让代码更容易理解和修改- 通过封装隐藏实现细节- 通过清晰的继承层次组织代码结构5. 复杂性问题:如何管理大型程序的复杂性- 通过对象间的组合和关联建立关系- 通过统一的接口降低模块间的耦合
*/

运行截图(部分):

OOP框架开发的关键问题解析

步骤1:抽象设计阶段

问题:如何识别和抽象现实世界的概念?

  • 解决思路:找出对象的共同属性和行为,定义抽象基类

  • 语法要点

    • virtual 函数:支持多态调用

    • = 0 纯虚函数:强制子类实现

    • protected 访问控制:允许子类访问但外部不能

步骤2:继承层次设计

问题:如何平衡代码复用和灵活性?

  • 解决思路:通过继承复用公共代码,通过重写体现差异

  • 语法要点

    • override 关键字:确保正确重写

    • 构造函数初始化列表:高效初始化基类

    • 虚析构函数:确保正确的多态析构

步骤3:多态机制应用

问题:如何用统一的接口处理不同类型的对象?

  • 解决思路:使用基类指针/引用,运行时绑定具体实现

  • 核心优势

    • 开闭原则:对扩展开放,对修改封闭

    • 统一处理:一套代码处理多种类型

    • 动态绑定:运行时决定调用哪个版本

步骤4:对象关系管理

问题:如何建模复杂的对象间关系?

  • 组合关系:整体包含部分(图书馆包含书籍)

  • 关联关系:对象间的使用关系(用户借阅书籍)

  • 聚合关系:松散的包含关系

这个案例展现的核心OOP价值

封装的价值

// 数据保护:外部不能直接修改内部状态
private: bool isAvailable;  // 只能通过方法修改// 接口稳定:实现可以改变,接口保持不变
public:void borrow();  // 外部只需知道如何调用

继承的价值

// 代码复用:避免重复实现相同功能
class PhysicalBook : public Book {  // 继承所有基本功能// 只需实现特有的部分void displayInfo() const override;
};

多态的价值

// 统一处理:一个接口处理多种类型
void LibraryManager::displayAllBooks() {for (const auto& book : books) {book->displayInfo();  // 自动调用正确的版本}
}

实际开发中的应用场景

GUI框架开发

  • 基类:Widget

  • 派生类:Button, TextBox, Menu

  • 多态:统一的事件处理机制

游戏开发

  • 基类:GameObject

  • 派生类:Player, Enemy, Item

  • 多态:统一的更新和渲染循环

文件系统

  • 基类:FileSystemNode

  • 派生类:File, Directory

  • 多态:统一的操作接口

这个案例完整展现了OOP如何解决软件开发中的核心问题:抽象建模、代码复用、系统扩展、复杂性管理。通过逐步构建,我们看到了OOP三大特性如何协同工作,创建出既灵活又可维护的软件架构。

扩展:现在C++ VS C++98:

// ========================================
// 现代C++版本 - 详细语法解释
// ========================================class ModernLibraryManager {
private:// 语法解释1: std::vector<std::unique_ptr<Book>>// - std::vector: 动态数组容器// - std::unique_ptr<Book>: 智能指针,自动管理内存// - Book: 基类类型,实现多态存储std::vector<std::unique_ptr<Book>> books;public:// 语法解释2: std::unique_ptr<Book> book 参数// - unique_ptr表示独占所有权// - 传入时转移所有权给容器void addBook(std::unique_ptr<Book> book) {// 语法解释3: std::move(book)// - 移动语义,转移所有权而不是拷贝// - 避免不必要的拷贝操作,提高效率books.push_back(std::move(book));std::cout << "书籍已添加到图书馆" << std::endl;}// 语法解释4: 基于范围的for循环 (C++11)void displayAllBooks() const {std::cout << "\n========== 图书馆藏书 ==========" << std::endl;// for (const auto& book : books) 语法解释:// - const: 不修改元素// - auto: 自动类型推导,这里是 std::unique_ptr<Book>&// - &: 引用,避免拷贝// - book: 循环变量名// - books: 要遍历的容器for (const auto& book : books) {// 语法解释5: book->displayInfo() 多态调用// - book是基类指针// - 运行时根据实际对象类型调用对应的方法// - 这就是多态的核心机制book->displayInfo();std::cout << std::endl;}}// 语法解释6: STL算法 + Lambda表达式Book* findBookByIsbn(const std::string& isbn) {// std::find_if语法解释:// - books.begin(), books.end(): 迭代器范围// - lambda表达式: [&isbn](const std::unique_ptr<Book>& book)// Lambda表达式详解:// [&isbn] - 捕获列表,按引用捕获isbn变量// (const std::unique_ptr<Book>& book) - 参数列表// { return book->getIsbn() == isbn; } - 函数体auto it = std::find_if(books.begin(), books.end(),[&isbn](const std::unique_ptr<Book>& book) {return book->getIsbn() == isbn;});// 语法解释7: 三元操作符 + 智能指针// (it != books.end()) ? it->get() : nullptr// - it->get(): 从unique_ptr获取原始指针// - 条件判断:找到返回指针,否则返回nullptrreturn (it != books.end()) ? it->get() : nullptr;}// 语法解释8: 多态方法调用bool borrowBook(const std::string& isbn) {Book* book = findBookByIsbn(isbn);if (book && book->canBorrow()) {// 多态调用解释:// - book是Book*类型的指针// - 实际指向的可能是PhysicalBook或EBook对象// - 运行时根据实际对象类型调用对应的borrow()方法book->borrow();  // 多态调用!return true;}std::cout << "无法借阅书籍 ISBN: " << isbn << std::endl;return false;}// 语法解释9: dynamic_cast 安全类型转换void showStatistics() const {int physicalCount = 0, ebookCount = 0;for (const auto& book : books) {// dynamic_cast语法解释:// - dynamic_cast<PhysicalBook*>(book.get())// - 尝试将基类指针转换为派生类指针// - 成功返回有效指针,失败返回nullptr// - 只能用于有虚函数的类(多态类)if (dynamic_cast<PhysicalBook*>(book.get())) {physicalCount++;} else if (dynamic_cast<EBook*>(book.get())) {ebookCount++;}}std::cout << "\n========== 图书馆统计 ==========" << std::endl;std::cout << "实体图书: " << physicalCount << " 本" << std::endl;std::cout << "电子书: " << ebookCount << " 本" << std::endl;std::cout << "总计: " << books.size() << " 本" << std::endl;}
};

C++ 98 :

// ========================================
// C++98版本实现 - 相同功能,不同语法
// ========================================// C++98版本的函数对象(替代lambda)
class IsbnMatcher {
private:const std::string& target_isbn;
public:// 构造函数接受要查找的ISBNIsbnMatcher(const std::string& isbn) : target_isbn(isbn) {}// 重载operator()使其可以像函数一样被调用bool operator()(const Book* book) const {return book->getIsbn() == target_isbn;}
};class Cpp98LibraryManager {
private:// C++98语法1: 使用原始指针代替智能指针// - 需要手动管理内存// - 需要在析构函数中删除所有指针std::vector<Book*> books;public:// C++98构造函数Cpp98LibraryManager() {std::cout << "C++98图书馆管理系统初始化" << std::endl;}// C++98析构函数 - 手动清理内存~Cpp98LibraryManager() {std::cout << "清理图书馆资源..." << std::endl;// 手动删除所有书籍对象for (std::vector<Book*>::iterator it = books.begin(); it != books.end(); ++it) {delete *it;  // 释放内存}books.clear();}// C++98语法2: 接受原始指针,手动管理所有权void addBook(Book* book) {if (book) {books.push_back(book);std::cout << "书籍已添加到图书馆" << std::endl;}}// C++98语法3: 传统for循环代替基于范围的for循环void displayAllBooks() const {std::cout << "\n========== 图书馆藏书 ==========" << std::endl;// 传统for循环语法:// - size_t i = 0: 初始化// - i < books.size(): 循环条件// - ++i: 每次迭代后执行for (size_t i = 0; i < books.size(); ++i) {// C++98访问元素:books[i] 或 books.at(i)books[i]->displayInfo();  // 多态调用std::cout << std::endl;}// 或者使用迭代器(C++98推荐方式):std::cout << "--- 使用迭代器遍历 ---" << std::endl;for (std::vector<Book*>::const_iterator it = books.begin();it != books.end(); ++it) {(*it)->displayInfo();  // 解引用迭代器得到指针,再调用方法std::cout << std::endl;}}// C++98语法4: 使用函数对象代替lambda表达式Book* findBookByIsbn(const std::string& isbn) {// 创建函数对象IsbnMatcher matcher(isbn);// 使用std::find_if和函数对象std::vector<Book*>::iterator it = std::find_if(books.begin(), books.end(), matcher  // 函数对象代替lambda);// C++98条件判断if (it != books.end()) {return *it;  // 解引用迭代器得到指针} else {return NULL;  // C++98使用NULL而不是nullptr}}// C++98语法5: 多态调用(与现代C++相同)bool borrowBook(const std::string& isbn) {Book* book = findBookByIsbn(isbn);if (book && book->canBorrow()) {book->borrow();  // 多态调用!语法相同return true;}std::cout << "无法借阅书籍 ISBN: " << isbn << std::endl;return false;}bool returnBook(const std::string& isbn) {Book* book = findBookByIsbn(isbn);if (book) {book->returnBook();  // 多态调用return true;}std::cout << "未找到书籍 ISBN: " << isbn << std::endl;return false;}// C++98语法6: 计算费用(展示多态的威力)void calculateAllFees(int days) const {std::cout << "\n========== 借阅费用计算 ==========" << std::endl;double totalFee = 0.0;// 传统for循环for (size_t i = 0; i < books.size(); ++i) {Book* book = books[i];if (!book->getAvailability()) {  // 已借出的书// 多态调用:不同类型的书有不同的计费方式double fee = book->calculateFee(days);std::cout << book->getTitle() << ": " << std::fixed << std::setprecision(2) << fee << "元" << std::endl;totalFee += fee;}}std::cout << "总费用: " << std::fixed << std::setprecision(2) << totalFee << "元" << std::endl;}// C++98语法7: dynamic_cast(C++98支持,但使用方式相同)void showStatistics() const {int physicalCount = 0, ebookCount = 0;// 使用传统for循环for (size_t i = 0; i < books.size(); ++i) {Book* book = books[i];// dynamic_cast在C++98中语法相同// 但需要确保编译器支持RTTI(运行时类型信息)if (dynamic_cast<PhysicalBook*>(book)) {physicalCount++;} else if (dynamic_cast<EBook*>(book)) {ebookCount++;}}std::cout << "\n========== 图书馆统计 ==========" << std::endl;std::cout << "实体图书: " << physicalCount << " 本" << std::endl;std::cout << "电子书: " << ebookCount << " 本" << std::endl;std::cout << "总计: " << books.size() << " 本" << std::endl;}// C++98辅助方法:获取书籍数量size_t getBookCount() const {return books.size();}
};
内存管理差异
// C++98 - 手动内存管理
class Cpp98LibraryManager {
private:std::vector<Book*> books;  // 原始指针public:~Cpp98LibraryManager() {// 手动删除所有对象for (std::vector<Book*>::iterator it = books.begin(); it != books.end(); ++it) {delete *it;}}
};// 现代C++ - 自动内存管理
class ModernLibraryManager {
private:std::vector<std::unique_ptr<Book>> books;  // 智能指针// 析构函数自动调用,无需手动delete
};
循环语法差异
// C++98 - 传统for循环
for (size_t i = 0; i < books.size(); ++i) {books[i]->displayInfo();  // 多态调用
}// 或使用迭代器
for (std::vector<Book*>::iterator it = books.begin();it != books.end(); ++it) {(*it)->displayInfo();
}// 现代C++ - 基于范围的for循环
for (const auto& book : books) {book->displayInfo();  // 语法更简洁
}
函数对象vs Lambda
// C++98 - 函数对象
class IsbnMatcher {const std::string& target_isbn;
public:IsbnMatcher(const std::string& isbn) : target_isbn(isbn) {}bool operator()(const Book* book) const {return book->getIsbn() == target_isbn;}
};// 使用方式
IsbnMatcher matcher(isbn);
std::find_if(books.begin(), books.end(), matcher);// 现代C++ - Lambda表达式
std::find_if(books.begin(), books.end(),[&isbn](const std::unique_ptr<Book>& book) {return book->getIsbn() == isbn;});

扩展:多态语法详细解析

核心多态语法要素

智能指针容器
// 现代C++ (C++11+)
std::vector<std::unique_ptr<Book>> books;
//            ↑              ↑
//      智能指针类型      基类类型// 语法解析:
// - std::unique_ptr<Book>: 独占所有权的智能指针
// - 自动管理内存,析构时自动删除对象
// - 基类指针实现多态存储

移动语义

// std::move(book) 语法解析:
void addBook(std::unique_ptr<Book> book) {books.push_back(std::move(book));//              ↑// 移动语义:转移所有权而不是拷贝// 避免不必要的拷贝操作,提高效率
}
Lambda表达式
// Lambda语法解析:
[&isbn](const std::unique_ptr<Book>& book) { return book->getIsbn() == isbn; }
// ↑     ↑                                   ↑
//捕获列表  参数列表                        函数体// [&isbn] - 按引用捕获外部变量isbn
// (const std::unique_ptr<Book>& book) - 参数类型
// { return ... } - 返回bool的函数体
多态调用机制
book->displayInfo();  // 多态调用// 运行时过程:
// 1. book是基类指针,指向派生类对象
// 2. 通过虚函数表(vtable)查找实际函数地址
// 3. 调用派生类的重写版本

多态的工作原理

虚函数表机制  

// 编译器为每个类生成虚函数表
class Book {virtual void displayInfo() = 0;  // 虚函数// 编译器添加:void* vptr;  // 虚函数表指针
};// 运行时调用过程:
Book* book = new PhysicalBook(...);
book->displayInfo();// 实际执行:
// 1. 通过book->vptr找到虚函数表
// 2. 在表中查找displayInfo的地址
// 3. 调用PhysicalBook::displayInfo()
dynamic_cast安全转换
// 语法:dynamic_cast<目标类型*>(源指针)
PhysicalBook* physical = dynamic_cast<PhysicalBook*>(book);if (physical) {// 转换成功,可以安全使用std::cout << physical->getLocation() << std::endl;
} else {// 转换失败,book不是PhysicalBook类型std::cout << "不是实体书" << std::endl;
}

关键语法对比表 

    功能C++98现代C++
    指针管理Book*std::unique_ptr<Book>
    内存释放delete ptr自动释放
    空指针NULLnullptr
    类型推导显式声明auto
    循环遍历传统for基于范围for
    函数对象类+operator()Lambda表达式
    移动语义不支持std::move()

    多态的核心价值

    无论使用哪个C++版本,多态的核心价值都相同:

    1.统一接口

    // 同一行代码处理不同类型 
    book->displayInfo(); // PhysicalBook显示位置,EBook显示格式

     2.运行时决定

    // 编译时不知道具体类型,运行时动态绑定
    std::vector<Book*> mixed_books = {physical_book, e_book, magazine};
    for (auto book : mixed_books) {book->borrow();  // 每种书的借阅方式不同
    }

    3.扩展性

    // 添加新书类型无需修改现有代码
    class AudioBook : public Book {void displayInfo() override { /* 音频书特有显示 */ }
    };
    // 现有的LibraryManager代码无需修改即可处理AudioBook
      http://www.dtcms.com/a/304174.html

      相关文章:

    1. SBB指令的“生活小剧场“
    2. Excel工作簿合并工具,快速查找一键整合
    3. 「源力觉醒 创作者计划」_DeepseekVS文心一言
    4. JavaWeb 入门:CSS 基础与实战详解(Java 开发者视角)
    5. 查询mac 安装所有python 版本
    6. 服务器之光:Nginx--反向代理模块详解及演练
    7. PHP性能优化与高并发处理:从基础到高级实践
    8. Rust 实战三 | HTTP 服务开发及 Web 框架推荐
    9. AI 数字人在处理音频时,如何确保声音的自然度?
    10. 使用 Canvas 替代 <video> 标签加载并渲染视频
    11. Vue 2.0响应式原理深度解析
    12. 艾体宝方案 | 数据孤岛终结者:GWI + DOMO 联手打造一体化增长引擎
    13. 系统调用追踪技术于VPS服务器性能分析的实施流程
    14. linux系统的启动过程
    15. Linux 系统启动过程及相关实验(破解密码;明文密文加密;修复grub2目录和boot目录)
    16. 前端优化之虚拟列表实现指南:从库集成到手动开发
    17. 【24】C# 窗体应用WinForm ——日历MonthCalendar属性、方法、实例应用
    18. 算法精讲:二分查找(一)—— 基础原理与实现
    19. vscode remote ssh相关问题
    20. 车载刷写架构 --- 刷写思考扩展
    21. Git 从入门到精通
    22. 【数据库】—— 分区字段为null的时候在未指定最大分区的情况下数据无法插入?
    23. 【C++算法】81.BFS解决FloodFill算法_岛屿的最大面积
    24. echarts图表点击legend报错问题(折线图)
    25. [ java泛型 ] 只闻其名---->“浅浅“了解
    26. Java面试宝典:MySQL中的锁
    27. 如何在在NPM发布一个React组件
    28. Kafka运维实战 16 - kafka 分区重新分配【实战】
    29. numpy瑞士军刀 第三卷:实战演练 第七章 组合大阵
    30. 【C++算法】77.优先级队列_数据流的中位数