71、C++ 文件输入输出及相关编程知识详解

C++ 文件输入输出及相关编程知识详解

1. 指针序列化

在序列化指针时,唯一重要的是它是否为 nullptr 。若为 nullptr ,则它不指向任何对象,无需向流中写入对象;若不为 nullptr ,则需将其指向的对象写入流中。可以用布尔值表示指针状态, nullptr 写为 false ,否则写为 true ,并记录其指向的对象。

例如,对于封装了 Node 对象链表(每个 Node 包含一个 Item 对象)的对象,若链表非空,指向第一个对象的指针写为 true ,并将第一个 Node 对象中的 Item 对象写入流。若 Node pNext 指针成员不为 nullptr ,先写入 true ,再写入下一个 Node 对象的 Item 对象。最后一个 Node pNext 成员为 nullptr ,写为 false 结束输出。无需在流中存储 Node 对象,它们只是真实数据 Item 的包装器。

另一种序列化方法是使用标记语言(如 XML)表达对象的数据和结构。这种方法独立于读写数据的编程语言,能保留对象定义。

2. 流操作基础
  • 标准库支持的流类型 :字符流、二进制(字节)流和字符串流。
  • 标准输入输出流 std::cin std::cout 用于输入输出, std::cerr std::clog 为标准错误流。
  • 文件流类 std::ifstream 用于输入, std::ofstream 用于输出, std::fstream 可同时用于输入和输出。
  • 流的打开模式 :决定能否读写流、输出时是否覆盖流内容以及流是二进制还是文本模式。
3. 文件特性
  • 文件仅包含字节,无论打开模式如何,可将二进制流按文本读取,反之亦然。
  • 以不存在的文件名打开文件输出流会创建文件。
  • 文件有开头、结尾和当前位置,可将文件流的当前位置更改为之前记录的位置,如相对于流开头的正偏移、相对于流结尾的负偏移或相对于当前位置的正负偏移。
4. 流操作相关
  • 格式化操作 :提取和插入运算符为基本类型数据提供格式化流输入输出操作。
  • 自定义对象支持 :可通过重载插入和提取运算符(作为类的友元函数)支持自定义对象的流操作。
  • 二进制模式操作 :流类提供 read() write() 成员函数用于二进制模式下的读写,二进制模式操作总是读写字节序列。
  • 字符串流类 :提供对内存中 std::string 对象的流输入输出操作。
5. 练习题

以下练习题可帮助巩固所学知识:
1. 编写 Time 类,以整数存储小时、分钟和秒,提供重载插入运算符 << ,以 hh:mm:ss 格式将时间打印到任何输出流。
2. 为 Time 类提供简单提取运算符 operator>>() ,读取 hh:mm:ss 格式的时间值,需处理 : 字符。
3. 编写程序将时间值记录到文件,再编写匹配程序读取文件中的时间值并输出到屏幕。
4. 编写程序从标准输入读取文本行,去除所有前导空白并将多个空格转换为单个空格后写入标准输出,在键盘输入和从文件读取字符上进行测试。再编写一个将小写字符转换为大写的程序并进行测试。
5. 定义封装 Box 对象链表的类,为该类实现 operator>>() operator<<() ,以便对象可存储在文件中并读取回来,定义 main() 函数验证类的功能。

6. 其他编程概念
  • 指针相关 :指针有多种用途,如数组指针、常量指针等。指针算术运算可用于操作数组元素。智能指针(如 unique_ptr<T> shared_ptr<T> weak_ptr<T> )可帮助管理动态内存,避免内存泄漏。
  • 函数相关 :函数可通过值传递或引用传递参数,支持函数重载和模板。函数模板可创建通用函数,提高代码复用性。
  • 类和对象相关 :类具有封装、继承和多态等特性。封装可隐藏数据,继承可创建类层次结构,多态通过虚函数实现动态绑定。
  • 异常处理 :可使用 try-catch 块捕获和处理异常,标准库提供了一些异常类,如 std::range_error 等。
7. 代码示例及操作流程

以下是一些关键操作的代码示例和操作流程:

7.1 指针序列化示例
#include <iostream>
#include <fstream>

// 假设的 Node 和 Item 类
class Item {
    // 实现省略
};

class Node {
public:
    Item item;
    Node* pNext;
    Node(const Item& i) : item(i), pNext(nullptr) {}
};

void serializeList(const Node* head, std::ofstream& out) {
    if (head == nullptr) {
        out << false;
        return;
    }
    out << true;
    // 这里可以添加 Item 的序列化代码
    serializeList(head->pNext, out);
}

int main() {
    Item item1, item2;
    Node node1(item1), node2(item2);
    node1.pNext = &node2;

    std::ofstream outFile("list.txt");
    serializeList(&node1, outFile);
    outFile.close();
    return 0;
}
7.2 文件读写操作示例
#include <iostream>
#include <fstream>
#include <string>

// 写入文件
void writeToFile(const std::string& filename, const std::string& data) {
    std::ofstream outFile(filename);
    if (outFile.is_open()) {
        outFile << data;
        outFile.close();
    }
}

// 读取文件
std::string readFromFile(const std::string& filename) {
    std::ifstream inFile(filename);
    std::string content;
    if (inFile.is_open()) {
        std::string line;
        while (std::getline(inFile, line)) {
            content += line + '\n';
        }
        inFile.close();
    }
    return content;
}

int main() {
    std::string data = "Hello, World!";
    std::string filename = "test.txt";

    writeToFile(filename, data);
    std::string readData = readFromFile(filename);
    std::cout << readData << std::endl;

    return 0;
}
8. 总结

通过学习文件输入输出和相关编程概念,我们可以更好地处理数据的存储和读取,提高程序的灵活性和可维护性。掌握指针序列化、流操作、文件读写等知识,能让我们在实际编程中更加得心应手。同时,通过练习题的实践,可以加深对这些知识的理解和运用能力。

以下是一个简单的 mermaid 流程图,展示文件读写的基本流程:

graph LR
    A[开始] --> B{选择操作}
    B -->|写入文件| C(打开输出文件流)
    C --> D(写入数据)
    D --> E(关闭文件流)
    B -->|读取文件| F(打开输入文件流)
    F --> G(读取数据)
    G --> H(关闭文件流)
    E --> I[结束]
    H --> I

通过以上内容,我们对 C++ 中的文件输入输出及相关编程知识有了较为全面的了解。希望这些知识能帮助你在编程道路上取得更好的成果。

C++ 文件输入输出及相关编程知识详解

9. 数据类型与运算符
  • 基本数据类型 :C++ 有多种基本数据类型,如整数类型( int long 等)、浮点类型( float double 等)和字符类型( char )。不同类型有不同的取值范围和精度。
    | 数据类型 | 描述 |
    | ---- | ---- |
    | int | 整数类型,通常为 32 位 |
    | float | 单精度浮点类型 |
    | double | 双精度浮点类型 |
    | char | 字符类型 |

  • 运算符 :包含算术运算符( + - * / 等)、关系运算符( > < == 等)、逻辑运算符( && || ! 等)和位运算符( & | ^ 等)。运算符具有不同的优先级和结合性。

10. 控制结构
  • 条件语句 :如 if-else 语句和 switch 语句,用于根据条件执行不同的代码块。
// if-else 语句示例
int num = 10;
if (num > 5) {
    std::cout << "Number is greater than 5" << std::endl;
} else {
    std::cout << "Number is less than or equal to 5" << std::endl;
}

// switch 语句示例
int choice = 2;
switch (choice) {
    case 1:
        std::cout << "You chose option 1" << std::endl;
        break;
    case 2:
        std::cout << "You chose option 2" << std::endl;
        break;
    default:
        std::cout << "Invalid choice" << std::endl;
}
  • 循环语句 :包括 for 循环、 while 循环和 do-while 循环,用于重复执行代码块。
// for 循环示例
for (int i = 0; i < 5; i++) {
    std::cout << i << std::endl;
}

// while 循环示例
int j = 0;
while (j < 5) {
    std::cout << j << std::endl;
    j++;
}

// do-while 循环示例
int k = 0;
do {
    std::cout << k << std::endl;
    k++;
} while (k < 5);
11. 类和对象的深入
  • 构造函数和析构函数 :构造函数用于初始化对象,析构函数用于在对象销毁时进行清理工作。
class Box {
public:
    // 构造函数
    Box(double l, double w, double h) : length(l), width(w), height(h) {}
    // 析构函数
    ~Box() {}
private:
    double length;
    double width;
    double height;
};
  • 继承和多态 :继承允许一个类继承另一个类的属性和方法,多态通过虚函数实现动态绑定。
// 基类
class Shape {
public:
    virtual double area() = 0; // 纯虚函数
};

// 派生类
class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}
    double area() override {
        return 3.14 * radius * radius;
    }
private:
    double radius;
};
12. 内存管理
  • 动态内存分配 :使用 new delete 运算符进行动态内存分配和释放。
int* ptr = new int; // 分配一个整数的内存
*ptr = 10;
delete ptr; // 释放内存

int* arr = new int[5]; // 分配一个包含 5 个整数的数组
for (int i = 0; i < 5; i++) {
    arr[i] = i;
}
delete[] arr; // 释放数组内存
  • 智能指针 :如 unique_ptr shared_ptr weak_ptr ,可自动管理内存,避免内存泄漏。
#include <memory>

// unique_ptr 示例
std::unique_ptr<int> uptr = std::make_unique<int>(10);

// shared_ptr 示例
std::shared_ptr<int> sptr = std::make_shared<int>(20);
13. 模板
  • 函数模板 :可创建通用函数,适用于不同的数据类型。
template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

int result1 = max(10, 20);
double result2 = max(3.14, 2.71);
  • 类模板 :用于创建通用类。
template <typename T>
class Array {
public:
    Array(int size) : data(new T[size]), size(size) {}
    ~Array() { delete[] data; }
private:
    T* data;
    int size;
};

Array<int> intArray(5);
Array<double> doubleArray(10);
14. 异常处理流程

异常处理是保证程序健壮性的重要手段,以下是异常处理的 mermaid 流程图:

graph LR
    A[开始] --> B(执行代码)
    B --> C{是否抛出异常}
    C -->|是| D(查找匹配的 catch 块)
    D --> E(执行 catch 块代码)
    E --> F(继续执行后续代码)
    C -->|否| F
    F --> G[结束]
15. 总结

C++ 是一门功能强大且复杂的编程语言,涵盖了丰富的数据类型、运算符、控制结构、类和对象等知识。通过掌握文件输入输出、指针序列化、内存管理、模板和异常处理等重要概念,我们能够编写出高效、健壮的程序。在实际编程中,要不断实践和总结,灵活运用这些知识,以应对各种编程挑战。

通过以下列表,我们可以快速回顾本文的重点内容:
1. 指针序列化的方法和应用
2. 流操作和文件读写的基本流程
3. 基本数据类型和运算符的使用
4. 控制结构的应用
5. 类和对象的构造、继承和多态
6. 动态内存分配和智能指针的使用
7. 函数模板和类模板的创建
8. 异常处理的流程和方法

希望这些知识能帮助你在 C++ 编程领域取得更大的进步。

MATLAB代码实现了一个基于多种智能优化算法优化RBF神经网络的回归预测模型,其核心是通过智能优化算法自动寻找最优的RBF扩展参数(spread),以提升预测精度。 1.主要功能 多算法优化RBF网络:使用多种智能优化算法优化RBF神经网络的核心参数spread。 回归预测:对输入特征进行回归预测,适用于连续值输出问题。 性能对比:对比不同优化算法在训练集和测试集上的预测性能,绘制适应度曲线、预测对比图、误差指标柱状图等。 2.算法步骤 数据准备:导入数据,随机打乱,划分训练集和测试集(默认7:3)。 数据归一化:使用mapminmax将输入和输出归一化到[0,1]区间。 标准RBF建模:使用固定spread=100建立基准RBF模型。 智能优化循环: 调用优化算法(从指定文件夹中读取算法文件)优化spread参数。 使用优化后的spread重新训练RBF网络。 评估预测结果,保存性能指标。 结果可视化: 绘制适应度曲线、训练集/测试集预测对比图。 绘制误差指标(MAE、RMSE、MAPE、MBE)柱状图。 十种智能优化算法分别是: GWO:灰狼算法 HBA:蜜獾算法 IAO:改进天鹰优化算法,改进①:Tent混沌映射种群初始化,改进②:自适应权重 MFO:飞蛾扑火算法 MPA:海洋捕食者算法 NGO:北方苍鹰算法 OOA:鱼鹰优化算法 RTH:红尾鹰算法 WOA:鲸鱼算法 ZOA:斑马算法
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值