《C++ Primer》导学系列:第 1 章 - 开始

1.1 编写一个简单的C++程序

概述

本小节介绍了如何编写和运行一个简单的C++程序,帮助初学者了解C++程序的基本结构和编译运行过程。

编写第一个C++程序

我们从一个简单的C++程序开始,它的功能是在控制台输出 "Hello, World!"。这是学习任何编程语言的传统起点。

  • 程序代码
cpp 复制代码
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}
代码解析
  1. 预处理指令
cpp 复制代码
#include <iostream>
  • #include 是一个预处理指令,用于包含标准库头文件。
  • <iostream> 是输入输出流库,用于处理输入和输出操作。
  1. 主函数
cpp 复制代码
int main() {
    // ...
    return 0;
}
  • int main() 是程序的入口点,每个C++程序都必须包含一个main函数。
  • 函数返回类型为int,表示程序执行的状态,0 通常表示成功。
  1. 输出语句
cpp 复制代码
std::cout << "Hello, World!" << std::endl;
  • std::cout 是标准输出流对象,用于输出数据到控制台。
  • << 是插入运算符,将右侧的数据插入到输出流中。
  • "Hello, World!" 是要输出的字符串。
  • std::endl 是一个流操纵符,用于插入一个换行符并刷新输出缓冲区。
编译和运行

编写完第一个C++程序后,我们需要将其编译成可执行文件,然后运行它。

  1. 编译
  • 使用C++编译器将源代码编译成机器代码。
  • 示例(使用g++编译器):
bash 复制代码
g++ -o hello hello.cpp
  • -o 选项指定生成的可执行文件名称,这里是 hello
  1. 运行
  • 运行生成的可执行文件。
  • 示例:
bash 复制代码
./hello
  • 运行结果:
diff 复制代码
Hello, World!
C++程序的基本结构

通过这个简单的程序,我们可以看到一个C++程序的基本结构:

  • 预处理指令
  • 主函数
  • 输出语句

这些是每个C++程序的基础,后续章节将会详细介绍更多复杂的语法和功能。

重点与难点分析

重点

  1. 预处理指令 :了解#include的作用,知道如何包含标准库头文件。
  2. 主函数结构 :掌握main函数的基本结构和作用。
  3. 输出语句 :理解std::cout、插入运算符<<std::endl的使用。

难点

  1. 编译过程:初学者可能对编译和链接过程不熟悉,需要多练习。
  2. 标准库<iostream> 是一个常用的标准库头文件,需要理解其基本功能。
练习题解析
  1. 练习1.1:编写并运行一个简单的C++程序,输出你的名字。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    std::cout << "Your Name" << std::endl;
    return 0;
}
  1. 练习1.2:修改第一个C++程序,使其输出两行文字。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    std::cout << "Welcome to C++ Programming!" << std::endl;
    return 0;
}
  1. 练习1.3 :尝试将std::cout替换为cout,观察编译错误,并修改代码以正确编译。
  • 示例代码:
cpp 复制代码
#include <iostream>

using std::cout;
using std::endl;

int main() {
    cout << "Hello, World!" << endl;
    return 0;
}
总结与提高

本节总结

  1. 了解了一个简单的C++程序的基本结构,包括预处理指令、主函数和输出语句。
  2. 学会了如何编写、编译和运行一个简单的C++程序。

提高建议

  1. 多编写简单程序:通过不断练习,熟悉C++程序的基本结构和编写流程。
  2. 探索更多标准库 :除了<iostream>,C++还有许多有用的标准库,可以逐步学习和使用。
  3. 了解编译器和开发环境:熟悉编译器的使用和常见选项,掌握IDE或命令行的开发环境,提高开发效率。

1.2 初识输入输出

概述

本小节介绍了C++中基本的输入输出操作,通过标准库中的cincout对象实现。这些对象是iostream库的一部分,用于处理控制台的输入输出。

使用cin进行输入

在C++中,cin对象用于从标准输入设备(通常是键盘)读取数据。ciniostream库的一部分。

  • 基本用法
cpp 复制代码
#include <iostream>

int main() {
    int number;
    std::cout << "Please enter a number: ";
    std::cin >> number;
    std::cout << "You entered: " << number << std::endl;
    return 0;
}
代码解析
  1. 读取输入
cpp 复制代码
std::cin >> number;
  • std::cin 是标准输入流对象。
  • >> 是提取运算符,用于从输入流中提取数据并存储到变量中。
  1. 输入提示
cpp 复制代码
std::cout << "Please enter a number: ";
  • 使用 std::cout 输出提示信息,引导用户输入。
  1. 输出结果
diff 复制代码
Please enter a number: 100
You entered: 100
处理多个输入

我们可以使用cin一次读取多个输入,并将其存储在不同的变量中。

  • 示例代码
cpp 复制代码
#include <iostream>

int main() {
    int num1, num2;
    std::cout << "Please enter two numbers: ";
    std::cin >> num1 >> num2;
    std::cout << "You entered: " << num1 << " and " << num2 << std::endl;
    return 0;
}
代码解析
  1. 读取多个输入
cpp 复制代码
std::cin >> num1 >> num2;
  • 使用提取运算符 >> 连续读取两个整数输入,并存储在 num1num2 中。
  1. 输出多个输入
diff 复制代码
Please enter two numbers: 10 20
You entered: 10 and 20
输入和输出的类型匹配

在使用cincout时,需要注意类型匹配。如果输入的数据类型与变量类型不匹配,会导致意外行为或错误。

  • 示例代码
cpp 复制代码
#include <iostream>

int main() {
    int num;
    std::cout << "Please enter an integer: ";
    std::cin >> num;
    if (std::cin.fail()) {
        std::cout << "Input error! Please enter a valid integer." << std::endl;
    } else {
        std::cout << "You entered: " << num << std::endl;
    }
    return 0;
}
代码解析
  1. 检查输入是否失败
cpp 复制代码
if (std::cin.fail()) {
    std::cout << "Input error! Please enter a valid integer." << std::endl;
}
  • std::cin.fail() 用于检测输入是否失败。如果输入的数据类型与变量类型不匹配,fail() 返回 true
  1. 重置输入流
cpp 复制代码
std::cin.clear();  // 重置输入流状态
std::cin.ignore(1000, '\n');  // 忽略输入缓冲区中的字符
  • std::cin.clear() 清除错误标志。
  • std::cin.ignore() 忽略输入缓冲区中的字符,避免影响后续输入操作。
重点与难点分析

重点

  1. 使用 cin****进行输入 :掌握cin对象和提取运算符>>的基本用法。
  2. 处理多个输入 :学习使用cin一次读取多个输入。
  3. 输入输出的类型匹配:理解类型匹配的重要性,学习如何处理输入错误。

难点

  1. 处理输入错误:初学者可能对输入错误处理不熟悉,需要多练习。
  2. 输入输出流状态管理:理解输入输出流的状态管理方法,如清除错误标志和忽略输入缓冲区。
练习题解析
  1. 练习1.4:编写一个程序,读取两个整数并输出它们的和。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    int num1, num2;
    std::cout << "Please enter two integers: ";
    std::cin >> num1 >> num2;
    int sum = num1 + num2;
    std::cout << "The sum is: " << sum << std::endl;
    return 0;
}
  1. 练习1.5:编写一个程序,读取三个浮点数并输出它们的平均值。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    float num1, num2, num3;
    std::cout << "Please enter three floating-point numbers: ";
    std::cin >> num1 >> num2 >> num3;
    float average = (num1 + num2 + num3) / 3;
    std::cout << "The average is: " << average << std::endl;
    return 0;
}
  1. 练习1.6:编写一个程序,读取一个整数并检查输入是否合法。如果输入不是整数,输出错误信息。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    int num;
    std::cout << "Please enter an integer: ";
    std::cin >> num;
    if (std::cin.fail()) {
        std::cout << "Input error! Please enter a valid integer." << std::endl;
        std::cin.clear();  // 重置输入流状态
        std::cin.ignore(1000, '\n');  // 忽略输入缓冲区中的字符
    } else {
        std::cout << "You entered: " << num << std::endl;
    }
    return 0;
}
总结与提高

本节总结

  1. 学习了C++中基本的输入输出操作,包括cincout对象的使用。
  2. 掌握了使用cin进行输入,处理多个输入,以及输入输出的类型匹配。
  3. 了解了如何处理输入错误和管理输入输出流的状态。

提高建议

  1. 多练习输入输出操作 :通过不断练习,熟悉cincout的基本用法和常见操作。
  2. 探索更多输入输出流功能:C++标准库提供了丰富的输入输出流功能,可以逐步学习和使用。
  3. 了解输入输出流的高级特性:如格式化输出、自定义流操纵符等,提升程序的灵活性和可读性。

1.3 注释简介

概述

注释是程序员在代码中加入的说明性文本,用于解释代码的功能、逻辑或特殊用法。注释不会被编译器执行,它们仅供阅读代码的人使用。合理的注释可以提高代码的可读性和可维护性。

C++支持两种注释方式:单行注释和多行注释。

单行注释

单行注释以 // 开头,直到行尾的所有内容都被视为注释。

  • 示例
cpp 复制代码
#include <iostream>

int main() {
    // 输出 "Hello, World!"
    std::cout << "Hello, World!" << std::endl; // 单行注释
    return 0; // 返回 0
}
代码解析
  1. 单行注释的使用
  • // 输出 "Hello, World!" 是一条单行注释,解释了下一行代码的功能。
  • // 返回 0 是一条单行注释,解释了 return 0 语句。
  1. 注释位置
  • 单行注释可以放在代码行的上方,也可以放在代码行的末尾。
多行注释

多行注释以 /* 开头,以 */ 结尾,之间的所有内容都被视为注释。

  • 示例
cpp 复制代码
#include <iostream>

int main() {
    /*
    这是一段多行注释
    解释了以下代码的功能:
    输出 "Hello, World!" 并返回 0
    */
    std::cout << "Hello, World!" << std::endl;
    return 0;
}
代码解析
  1. 多行注释的使用
  • /**/ 之间的所有内容都是注释,可以跨越多行。
  • 多行注释通常用于解释复杂的代码段或提供详细的说明。
  1. 嵌套注释的注意事项
  • 多行注释不能嵌套,即在一个多行注释内不能再包含另一个多行注释。
  • 嵌套会导致编译错误。
注释的最佳实践

合理的注释可以显著提高代码的可读性和可维护性。以下是一些编写注释的最佳实践:

  1. 解释意图,而非解释语法
  • 注释应解释代码的目的和逻辑,而不是解释语法。例如,不要注释显而易见的语法,而是解释为什么这样写。
  1. 保持简洁明了
  • 注释应简洁明了,避免冗长。清晰的注释有助于快速理解代码。
  1. 及时更新注释
  • 代码修改后,应及时更新相应的注释,以确保注释与代码一致。
  1. 使用TODO注释
  • 对于需要进一步完善或修复的代码,可以使用 TODO 注释标记,提醒以后回顾和处理。
  • 示例:
cpp 复制代码
// TODO: 处理可能的错误情况
  1. 避免过度注释
  • 虽然注释很重要,但过多的注释可能会使代码显得杂乱无章。应在关键部分添加注释,而不是每行都注释。
练习题解析
  1. 练习1.7:编写一个简单的程序,使用单行注释解释每一行代码。
  • 示例代码:
cpp 复制代码
#include <iostream>  // 包含输入输出流库

int main() {
    int num;  // 定义一个整数变量
    std::cout << "Please enter a number: ";  // 输出提示信息
    std::cin >> num;  // 从标准输入读取一个整数
    std::cout << "You entered: " << num << std::endl;  // 输出读取的整数
    return 0;  // 返回 0
}
  1. 练习1.8:编写一个程序,使用多行注释解释整个程序的功能。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    /*
    这是一个简单的C++程序
    它从用户那里读取一个整数
    然后输出该整数
    */
    int num;
    std::cout << "Please enter a number: ";
    std::cin >> num;
    std::cout << "You entered: " << num << std::endl;
    return 0;
}
  1. 练习1.9:编写一个复杂的代码段,使用注释解释每一步操作。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <vector>

int main() {
    // 定义一个整数向量
    std::vector<int> numbers;

    // 向向量中添加数字
    for (int i = 1; i <= 5; ++i) {
        numbers.push_back(i);  // 添加数字 i 到向量末尾
    }

    // 计算向量中数字的总和
    int sum = 0;
    for (int num : numbers) {
        sum += num;  // 将每个数字累加到 sum
    }

    // 输出结果
    std::cout << "The sum is: " << sum << std::endl;  // 输出总和
    return 0;
}
总结与提高

本节总结

  1. 学习了C++中的两种注释方式:单行注释和多行注释。
  2. 了解了如何在代码中添加注释,以提高代码的可读性和可维护性。
  3. 通过示例代码,掌握了注释的基本用法和最佳实践。

提高建议

  1. 多练习编写注释:在编写代码时,养成良好的注释习惯,解释代码的功能和逻辑。
  2. 阅读他人的代码:通过阅读他人代码中的注释,学习如何编写清晰有效的注释。
  3. 及时更新注释:在修改代码时,确保相应的注释也得到更新,以保持代码和注释的一致性。

1.4 控制结构

概述

控制结构是编程语言中用于控制代码执行流程的语法元素。C++提供了多种控制结构,包括条件语句、循环语句和跳转语句。本小节将介绍C++中的基本控制结构,帮助初学者理解如何控制程序的执行流程。

条件语句

条件语句用于根据某个条件的真假来决定执行哪个代码块。C++中的条件语句主要包括if语句、if-else语句。

if语句

if语句根据条件表达式的真假来决定是否执行相应的代码块。

  • 语法
cpp 复制代码
if (condition) {
    // 如果 condition 为真,执行这里的代码
}
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    int value = 42;
    if (value > 0) {
        std::cout << "Value is positive" << std::endl;
    }
    return 0;
}
if-else语句

if-else语句在条件为真时执行一个代码块,为假时执行另一个代码块。

  • 语法
cpp 复制代码
if (condition) {
    // 如果 condition 为真,执行这里的代码
} else {
    // 否则,执行这里的代码
}
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    int value = -10;
    if (value > 0) {
        std::cout << "Value is positive" << std::endl;
    } else {
        std::cout << "Value is not positive" << std::endl;
    }
    return 0;
}
if-else if-else语句

if-else if-else语句用于检查多个条件,依次判断每个条件表达式。

  • 语法
cpp 复制代码
if (condition1) {
    // 如果 condition1 为真,执行这里的代码
} else if (condition2) {
    // 如果 condition2 为真,执行这里的代码
} else {
    // 如果前面的条件都不为真,执行这里的代码
}
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    int value = 0;
    if (value > 0) {
        std::cout << "Value is positive" << std::endl;
    } else if (value < 0) {
        std::cout << "Value is negative" << std::endl;
    } else {
        std::cout << "Value is zero" << std::endl;
    }
    return 0;
}
循环语句

循环语句用于重复执行某段代码,直到满足某个条件。C++中的循环语句主要包括while循环、do-while循环和for循环。

while循环

while循环在每次迭代之前检查条件,如果条件为真,则执行循环体。

  • 语法
cpp 复制代码
while (condition) {
    // 如果 condition 为真,执行这里的代码
}
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    int count = 0;
    while (count < 5) {
        std::cout << "Count is: " << count << std::endl;
        ++count;
    }
    return 0;
}
do-while循环

do-while循环先执行循环体,然后检查条件,如果条件为真,则继续执行循环体。

  • 语法
cpp 复制代码
do {
    // 先执行这里的代码
} while (condition);
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    int count = 0;
    do {
        std::cout << "Count is: " << count << std::endl;
        ++count;
    } while (count < 5);
    return 0;
}
for循环

for循环在循环开始前初始化变量,在每次迭代前检查条件,并在每次迭代后更新变量。

  • 语法
cpp 复制代码
for (initialization; condition; increment) {
    // 如果 condition 为真,执行这里的代码
}
  • 示例
cpp 复制代码
#include <iostream>

int main() {
    for (int count = 0; count < 5; ++count) {
        std::cout << "Count is: " << count << std::endl;
    }
    return 0;
}
重点与难点分析

重点

  1. 条件语句 :掌握ifif-elseif-else if-else语句的使用。
  2. 循环语句 :理解whiledo-whilefor循环的用法。

难点

  1. 条件和循环逻辑:初学者可能会对复杂的条件和循环逻辑感到困惑,需要通过实践加深理解。
  2. 避免滥用 goto:尽量避免使用goto,并学习更清晰的控制流程方法。
练习题解析
  1. 练习1.10 :编写一个程序,使用while循环输出10到1的数字。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    int count = 10;
    while (count > 0) {
        std::cout << "Count is: " << count << std::endl;
        --count;
    }
    return 0
}
  1. 练习1.11 :编写一个程序,使用for循环输出1到10的数字。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    for (int count = 1; count <= 10; ++count) {
        std::cout << "Count is: " << count << std::endl;
    }
    return 0;
}
  1. 练习1.12 :编写一个程序,使用if-else语句检查输入的整数是正数、负数还是零。
  • 示例代码:
cpp 复制代码
#include <iostream>

int main() {
    int number;
    std::cout << "Please enter an integer: ";
    std::cin >> number;
    if (number > 0) {
        std::cout << "The number is positive." << std::endl;
    } else if (number < 0) {
        std::cout << "The number is negative." << std::endl;
    } else {
        std::cout << "The number is zero." << std::endl;
    }
    return 0;
}
总结与提高

本节总结

  1. 学习了C++中的基本控制结构,包括条件语句、循环语句和跳转语句。
  2. 掌握了ifif-else语句的用法。
  3. 了解了whiledo-whilefor循环的不同用法。

提高建议

  1. 多练习控制结构的使用:通过编写各种示例程序,熟悉控制结构的用法和逻辑。
  2. 理解和优化循环逻辑:在实际编程中,理解和优化循环逻辑,编写高效的代码。

1.5 类简介

概述

类是C++中的一种用户定义类型,它将数据和操作数据的方法封装在一起,是面向对象编程(OOP)的基础。类定义了一组对象的共同属性和行为,通过实例化类,可以创建具体的对象。

定义和使用类

一个类由成员变量(数据成员)和成员函数(方法)组成。成员变量用于存储对象的状态,成员函数用于定义对象的行为。

定义类
  • 语法
cpp 复制代码
class ClassName {
public:
    // 公有成员
    // 成员变量
    // 成员函数
private:
    // 私有成员
    // 成员变量
    // 成员函数
};
  • 示例
cpp 复制代码
#include <iostream>
#include <string>

class SalesItem {
public:
    // 成员函数,声明和定义分离
    std::string isbn() const { return bookNo; }
    double avg_price() const;

    // 成员变量
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

// 成员函数的定义
double SalesItem::avg_price() const {
    if (units_sold) {
        return revenue / units_sold;
    } else {
        return 0;
    }
}

int main() {
    SalesItem item;
    item.bookNo = "12345";
    item.units_sold = 100;
    item.revenue = 1000.0;

    std::cout << "ISBN: " << item.isbn() << std::endl;
    std::cout << "Average Price: " << item.avg_price() << std::endl;

    return 0;
}
  • 注意,编译上面的代码采用如下的命令:
bash 复制代码
// 假如你将文件存储为test.cpp
// 需要加上参数 -std=c++11 表示使用C++11标准
g++ -std=c++11 test.cpp -o test
代码解析
  1. 类的定义
  • 类通过关键字class定义,后跟类名和类体。类体包含成员变量和成员函数。
  • publicprivate访问说明符用于控制成员的访问权限。
  1. 成员变量
  • 成员变量在类中声明,用于存储对象的状态。例如:std::string bookNo;
  1. 成员函数
  • 成员函数定义了操作成员变量的方法。可以在类内声明,在类外定义。例如:
cpp 复制代码
std::string isbn() const { return bookNo; }
double avg_price() const;
  1. 成员函数的定义
  • 成员函数可以在类外定义,使用ClassName::FunctionName语法。例如:
cpp 复制代码
double SalesItem::avg_price() const {
    if (units_sold) {
        return revenue / units_sold;
    } else {
        return 0;
    }
}
  1. 创建对象
  • 通过类名创建对象,访问对象的成员。例如:
cpp 复制代码
SalesItem item;
item.bookNo = "12345";
item.units_sold = 100;
item.revenue = 1000.0;
重点与难点分析

重点

  1. 类的定义和使用:理解类的基本结构,包括成员变量和成员函数的定义和使用。

难点

  1. 成员函数的定义和调用:初学者需要熟悉成员函数在类外定义和调用的语法。
练习题解析
  1. 练习1.13 :定义一个类Book,包含成员变量titleauthorprice,以及相应的构造函数和成员函数。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

class Book {
public:
    // 默认构造函数
    Book() = default;
    // 带参数的构造函数
    Book(const std::string &t, const std::string &a, double p) 
        : title(t), author(a), price(p) {}

    // 成员函数
    std::string getTitle() const { return title; }
    std::string getAuthor() const { return author; }
    double getPrice() const { return price; }

private:
    // 成员变量
    std::string title;
    std::string author;
    double price = 0.0;
};

int main() {
    Book book1;
    Book book2("C++ Primer", "Stanley B. Lippman", 59.99);

    std::cout << "Book1 Title: " << book1.getTitle() << std::endl;
    std::cout << "Book2 Title: " << book2.getTitle() << std::endl;

    return 0;
}
  1. 练习1.14 :修改SalesItem类,添加一个计算总销售额的成员函数。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

class SalesItem {
public:
    SalesItem() = default;
    SalesItem(const std::string &book, unsigned sold, double rev) 
        : bookNo(book), units_sold(sold), revenue(rev) {}

    std::string isbn() const { return bookNo; }
    double avg_price() const;
    double total_revenue() const { return revenue; }

private:
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

double SalesItem::avg_price() const {
    if (units_sold) {
        return revenue / units_sold;
    } else {
        return 0;
    }
}

int main() {
    SalesItem item("12345", 100, 1000.0);
    std::cout << "ISBN: " << item.isbn() << std::endl;
    std::cout << "Total Revenue: " << item.total_revenue() << std::endl;
    return 0;
}
  1. 练习1.15 :为Book类添加析构函数,输出书籍对象销毁时的信息。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

class Book {
public:
    Book() = default;
    Book(const std::string &t, const std::string &a, double p) 
        : title(t), author(a), price(p) {}

    std::string getTitle() const { return title; }
    std::string getAuthor() const { return author; }
    double getPrice() const { return price; }

    ~Book() {
        std::cout << "Book object for " << title << " is being destroyed" << std::endl;
    }

private:
    std::string title;
    std::string author;
    double price = 0.0;
};

int main() {
    Book book1("C++ Primer", "Stanley B. Lippman", 59.99);
    return 0;
}
总结与提高

本节总结

  1. 了解了类的基本概念和定义,包括成员变量和成员函数。
  2. 通过示例代码,掌握了类的基本用法和常见操作。

提高建议

  1. 多练习定义和使用类:通过编写各种类,熟悉类的定义、构造函数和析构函数的使用。
  2. 理解面向对象编程的基本概念:学习封装、继承和多态等面向对象编程的基本概念,编写更复杂的类。

1.6 书店程序

概述

在本小节中,我们将使用之前学到的C++基础知识,编写一个简单的书店程序。这个程序的目标是处理书籍销售记录,通过对销售数据进行统计,计算销售的总额。

需求描述

书店程序需要完成以下功能:

  1. 读取一系列书籍的销售记录。
  2. 统计每种书籍的总销售量和总销售额。
  3. 输出每种书籍的ISBN、销售总量和总销售额。
数据结构

为了处理书籍销售记录,我们需要定义一个类来表示每一本书的销售数据。该类应该包括以下成员:

  • ISBN(书籍编号)
  • 销售量
  • 总销售额

我们可以重用之前定义的SalesItem类或定义一个新的类Sales_data

定义Sales_data
  • 类定义
cpp 复制代码
#include <iostream>
#include <string>

class Sales_data {
public:
    // 成员变量
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;

    // 成员函数
    std::string isbn() const { return bookNo; }
    Sales_data& combine(const Sales_data&);
    double avg_price() const;
};

// 成员函数定义
Sales_data& Sales_data::combine(const Sales_data& rhs) {
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

double Sales_data::avg_price() const {
    if (units_sold) {
        return revenue / units_sold;
    } else {
        return 0;
    }
}
代码解析
  1. 成员变量
  • std::string bookNo:书籍的ISBN编号。
  • unsigned units_sold:销售量。
  • double revenue:总销售额。
  1. 成员函数
  • std::string isbn() const:返回书籍的ISBN编号。
  • Sales_data& combine(const Sales_data&):将另一条销售记录的数据合并到当前对象。
  • double avg_price() const:计算平均售价。
  1. 成员函数定义
  • combine函数:将传入的Sales_data对象的销售量和总销售额累加到当前对象。
  • avg_price函数:计算平均售价,如果销售量为零,则返回零。
实现书店程序

我们将编写一个主函数,用于读取销售记录、统计每种书籍的总销售量和总销售额,并输出结果。

  • 主函数实现
cpp 复制代码
#include <iostream>
#include <string>
#include "Sales_data.h"  // 包含Sales_data类定义

int main() {
    Sales_data total;  // 保存当前书籍的销售总记录
    // 读取第一条销售记录
    if (std::cin >> total.bookNo >> total.units_sold >> total.revenue) {
        Sales_data trans;  // 保存每次读取的新销售记录
        // 读取并处理剩余的销售记录
        while (std::cin >> trans.bookNo >> trans.units_sold >> trans.revenue) {
            if (total.isbn() == trans.isbn()) {
                total.combine(trans);  // 更新当前书籍的总销售记录
            } else {
                // 输出结果
                std::cout << total.isbn() << " "
                          << total.units_sold << " "
                          << total.revenue << " "
                          << total.avg_price() << std::endl;
                total = trans;  // 处理下一本书的销售记录
            }
        }
        // 输出最后一本书的销售记录
        std::cout << total.isbn() << " "
                  << total.units_sold << " "
                  << total.revenue << " "
                  << total.avg_price() << std::endl;
    } else {
        std::cerr << "No data?!" << std::endl;
        return -1;  // 表示失败
    }
    return 0;
}
代码解析
  1. 变量定义
  • Sales_data total:保存当前书籍的销售总记录。
  • Sales_data trans:保存每次读取的新销售记录。
  1. 读取第一条销售记录
  • 使用std::cin读取第一条销售记录,并存储到total对象中。
  1. 处理剩余销售记录
  • 使用while循环读取剩余的销售记录,并存储到trans对象中。
  • 如果当前记录的ISBN与total对象的ISBN相同,则调用combine函数更新总记录。
  • 如果ISBN不同,则输出total对象的累计结果,并更新total对象为当前记录。
  1. 输出最后一本书的销售记录
  • 循环结束后,输出total对象的最终累计结果。
  1. 错误处理
  • 如果没有读取到任何数据,输出错误信息,并返回失败状态。
重点与难点分析

重点

  1. 类的定义和使用 :复习和应用之前定义的Sales_data类,包括成员变量和成员函数。
  2. 输入输出操作 :熟练使用std::cinstd::cout进行数据读取和输出。
  3. 条件判断和循环控制 :使用if语句和while循环控制程序流程。

难点

  1. 数据合并逻辑 :正确理解和实现combine函数的逻辑,确保销售记录的准确累计。
  2. 输入数据处理:处理标准输入中的数据,并根据ISBN判断是否需要合并或输出结果。
练习题解析
  1. 练习1.16:编写一个程序,从标准输入读取多条销售记录,并计算每条记录的总和。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

int main() {
    Sales_data total;
    while (std::cin >> total.bookNo >> total.units_sold >> total.revenue) {
        std::cout << "ISBN: " << total.isbn() << ", "
                  << "Units Sold: " << total.units_sold << ", "
                  << "Revenue: " << total.revenue << ", "
                  << "Average Price: " << total.avg_price() << std::endl;
    }
    return 0;
}
  1. 练习1.17:修改主程序,增加输入错误处理逻辑,当输入数据格式不正确时,输出错误信息。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

int main() {
    Sales_data total;
    while (true) {
        std::cout << "Enter bookNo, units_sold, and revenue: ";
        if (!(std::cin >> total.bookNo >> total.units_sold >> total.revenue)) {
            std::cerr << "Input error! Please enter valid data." << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        } else {
            std::cout << "ISBN: " << total.isbn() << ", "
                      << "Units Sold: " << total.units_sold << ", "
                      << "Revenue: " << total.revenue << ", "
                      << "Average Price: " << total.avg_price() << std::endl;
        }
    }
    return 0;
}
  1. 练习1.18:扩展程序,允许用户输入多组数据,每组数据包含多个销售记录,并计算每组数据的总和。
  • 示例代码:
cpp 复制代码
#include <iostream>
#include <string>

int main() {
    Sales_data total;
    while (true) {
        std::cout << "Enter bookNo, units_sold, and revenue (enter 'end' to finish): ";
        std::string bookNo;
        if (!(std::cin >> bookNo)) break;
        if (bookNo == "end") break;
        total.bookNo = bookNo;
        if (!(std::cin >> total.units_sold >> total.revenue)) {
            std::cerr << "Input error! Please enter valid data." << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }
        Sales_data trans;
        while (true) {
            std::cout << "Enter another record for the same book (enter 'done' to finish this book): ";
            std::string transBookNo;
            if (!(std::cin >> transBookNo)) break;
            if (transBookNo == "done") break;
            trans.bookNo = transBookNo;
            if (!(std::cin >> trans.units_sold >> trans.revenue)) {
                std::cerr << "Input error! Please enter valid data." << std::endl;
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                continue;
            }
            if (total.isbn() == trans.isbn()) {
                total.combine(trans);
            } else {
                std::cerr << "ISBN mismatch! Please enter the correct record." << std::endl;
            }
        }
        std::cout << "Total for book " << total.isbn() << ": "
                  << "Units Sold: " << total.units_sold << ", "
                  << "Revenue: " << total.revenue << ", "
                  << "Average Price: " << total.avg_price() << std::endl;
    }
    return 0;
}
总结与提高

本节总结

  1. 通过实现书店程序,综合应用了类、输入输出、条件判断和循环控制等C++基础知识。
  2. 学习了如何定义和使用一个类来处理实际问题中的数据。
  3. 掌握了如何从标准输入读取数据,处理和统计这些数据,并输出结果。

提高建议

  1. 多练习实际应用场景:通过更多实际应用场景的练习,巩固和加深对C++基础知识的理解和应用。
  2. 优化程序逻辑:在编写程序时,注重代码的结构和逻辑,提高代码的可读性和可维护性。
  3. 处理输入错误和异常情况:在实际应用中,输入数据可能会有错误,需要学习如何处理这些错误和异常情况,编写健壮的程序。

本主页会定期更新,为了能够及时获得更新,敬请关注我:点击左下角的关注。也可以关注公众号:请在微信上搜索公众号"iShare爱分享"并关注,或者扫描以下公众号二维码关注,以便在内容更新时直接向您推送。

相关推荐
高山我梦口香糖6 分钟前
[react]searchParams转普通对象
开发语言·前端·javascript
冷眼看人间恩怨18 分钟前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
信号处理学渣27 分钟前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客28 分钟前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin30 分钟前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
jasmine s37 分钟前
Pandas
开发语言·python
biomooc1 小时前
R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
开发语言·r语言
骇客野人1 小时前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言
black^sugar1 小时前
纯前端实现更新检测
开发语言·前端·javascript
404NooFound1 小时前
Python轻量级NoSQL数据库TinyDB
开发语言·python·nosql