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

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

概述

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

编写第一个C++程序

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

  • 程序代码
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

代码解析
  1. 预处理指令
#include <iostream>
  • #include 是一个预处理指令,用于包含标准库头文件。
  • <iostream> 是输入输出流库,用于处理输入和输出操作。

  1. 主函数
int main() {
    // ...
    return 0;
}
  • int main() 是程序的入口点,每个C++程序都必须包含一个main函数。
  • 函数返回类型为int,表示程序执行的状态,0 通常表示成功。

  1. 输出语句
std::cout << "Hello, World!" << std::endl;
  • std::cout 是标准输出流对象,用于输出数据到控制台。
  • << 是插入运算符,将右侧的数据插入到输出流中。
  • "Hello, World!" 是要输出的字符串。
  • std::endl 是一个流操纵符,用于插入一个换行符并刷新输出缓冲区。

编译和运行

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

  1. 编译
  • 使用C++编译器将源代码编译成机器代码。
  • 示例(使用g++编译器):
g++ -o hello hello.cpp
  • -o 选项指定生成的可执行文件名称,这里是 hello

  1. 运行
  • 运行生成的可执行文件。
  • 示例:
./hello

  • 运行结果:
Hello, World!

C++程序的基本结构

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

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

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

重点与难点分析

重点

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

难点

  1. 编译过程:初学者可能对编译和链接过程不熟悉,需要多练习。
  2. 标准库<iostream> 是一个常用的标准库头文件,需要理解其基本功能。

练习题解析
  1. 练习1.1:编写并运行一个简单的C++程序,输出你的名字。
  • 示例代码:
#include <iostream>

int main() {
    std::cout << "Your Name" << std::endl;
    return 0;
}

  1. 练习1.2:修改第一个C++程序,使其输出两行文字。
  • 示例代码:
#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,观察编译错误,并修改代码以正确编译。
  • 示例代码:
#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库的一部分。

  • 基本用法
#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. 读取输入
std::cin >> number;
  • std::cin 是标准输入流对象。
  • >> 是提取运算符,用于从输入流中提取数据并存储到变量中。

  1. 输入提示
std::cout << "Please enter a number: ";
  • 使用 std::cout 输出提示信息,引导用户输入。

  1. 输出结果
Please enter a number: 100
You entered: 100

处理多个输入

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

  • 示例代码
#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. 读取多个输入
std::cin >> num1 >> num2;
  • 使用提取运算符 >> 连续读取两个整数输入,并存储在 num1num2 中。

  1. 输出多个输入
Please enter two numbers: 10 20
You entered: 10 and 20

输入和输出的类型匹配

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

  • 示例代码
#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. 检查输入是否失败
if (std::cin.fail()) {
    std::cout << "Input error! Please enter a valid integer." << std::endl;
}
  • std::cin.fail() 用于检测输入是否失败。如果输入的数据类型与变量类型不匹配,fail() 返回 true

  1. 重置输入流
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:编写一个程序,读取两个整数并输出它们的和。
  • 示例代码:
#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:编写一个程序,读取三个浮点数并输出它们的平均值。
  • 示例代码:
#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:编写一个程序,读取一个整数并检查输入是否合法。如果输入不是整数,输出错误信息。
  • 示例代码:
#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++支持两种注释方式:单行注释和多行注释。

单行注释

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

  • 示例
#include <iostream>

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

多行注释

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

  • 示例
#include <iostream>

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

注释的最佳实践

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

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

练习题解析
  1. 练习1.7:编写一个简单的程序,使用单行注释解释每一行代码。
  • 示例代码:
#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:编写一个程序,使用多行注释解释整个程序的功能。
  • 示例代码:
#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:编写一个复杂的代码段,使用注释解释每一步操作。
  • 示例代码:
#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语句根据条件表达式的真假来决定是否执行相应的代码块。

  • 语法
if (condition) {
    // 如果 condition 为真,执行这里的代码
}

  • 示例
#include <iostream>

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

if-else语句

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

  • 语法
if (condition) {
    // 如果 condition 为真,执行这里的代码
} else {
    // 否则,执行这里的代码
}

  • 示例
#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语句用于检查多个条件,依次判断每个条件表达式。

  • 语法
if (condition1) {
    // 如果 condition1 为真,执行这里的代码
} else if (condition2) {
    // 如果 condition2 为真,执行这里的代码
} else {
    // 如果前面的条件都不为真,执行这里的代码
}

  • 示例
#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循环在每次迭代之前检查条件,如果条件为真,则执行循环体。

  • 语法
while (condition) {
    // 如果 condition 为真,执行这里的代码
}

  • 示例
#include <iostream>

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

do-while循环

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

  • 语法
do {
    // 先执行这里的代码
} while (condition);

  • 示例
#include <iostream>

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

for循环

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

  • 语法
for (initialization; condition; increment) {
    // 如果 condition 为真,执行这里的代码
}

  • 示例
#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的数字。
  • 示例代码:
#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的数字。
  • 示例代码:
#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语句检查输入的整数是正数、负数还是零。
  • 示例代码:
#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)的基础。类定义了一组对象的共同属性和行为,通过实例化类,可以创建具体的对象。

定义和使用类

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

定义类
  • 语法
class ClassName {
public:
    // 公有成员
    // 成员变量
    // 成员函数
private:
    // 私有成员
    // 成员变量
    // 成员函数
};

  • 示例
#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;
}
  • 注意,编译上面的代码采用如下的命令:
// 假如你将文件存储为test.cpp
// 需要加上参数 -std=c++11 表示使用C++11标准
g++ -std=c++11 test.cpp -o test

代码解析
  1. 类的定义
  • 类通过关键字class定义,后跟类名和类体。类体包含成员变量和成员函数。
  • publicprivate访问说明符用于控制成员的访问权限。
  1. 成员变量
  • 成员变量在类中声明,用于存储对象的状态。例如:std::string bookNo;
  1. 成员函数
  • 成员函数定义了操作成员变量的方法。可以在类内声明,在类外定义。例如:
std::string isbn() const { return bookNo; }
double avg_price() const;
  1. 成员函数的定义
  • 成员函数可以在类外定义,使用ClassName::FunctionName语法。例如:
double SalesItem::avg_price() const {
    if (units_sold) {
        return revenue / units_sold;
    } else {
        return 0;
    }
}
  1. 创建对象
  • 通过类名创建对象,访问对象的成员。例如:
SalesItem item;
item.bookNo = "12345";
item.units_sold = 100;
item.revenue = 1000.0;

重点与难点分析

重点

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

难点

  1. 成员函数的定义和调用:初学者需要熟悉成员函数在类外定义和调用的语法。

练习题解析
  1. 练习1.13:定义一个类Book,包含成员变量titleauthorprice,以及相应的构造函数和成员函数。
  • 示例代码:
#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类,添加一个计算总销售额的成员函数。
  • 示例代码:
#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类添加析构函数,输出书籍对象销毁时的信息。
  • 示例代码:
#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
  • 类定义
#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函数:计算平均售价,如果销售量为零,则返回零。

实现书店程序

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

  • 主函数实现
#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:编写一个程序,从标准输入读取多条销售记录,并计算每条记录的总和。
  • 示例代码:
#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:修改主程序,增加输入错误处理逻辑,当输入数据格式不正确时,输出错误信息。
  • 示例代码:
#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:扩展程序,允许用户输入多组数据,每组数据包含多个销售记录,并计算每组数据的总和。
  • 示例代码:
#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爱分享”并关注,或者扫描以下公众号二维码关注,以便在内容更新时直接向您推送。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/708378.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CGAL】圆柱体检测结果后处理

文章目录 文章说明算法思路代码展示结果展示 文章说明 这篇文章主要介绍&#xff0c;对使用CGAL中的 Region Growing 算法爬取圆柱体的结果进行后处理&#xff0c;以获取位置、轴向量、半径都较为合理的单个圆柱体。 在之前的一篇文章中&#xff0c;使用了open3D生成的标准圆…

560亿美元薪酬获批!马斯克:特斯拉未来市值将不止5万亿美元

KlipC报道&#xff1a;6月13日&#xff0c;美国电动汽车制造商特斯拉公司举办年度股东大会&#xff0c;其CEO马斯克对特斯拉生产销售、未来车型计划和在无人驾驶能等领域的发展进行了报告。此外&#xff0c;特斯拉股东批准了马斯克的560亿美元薪酬方案以及特斯拉总部迁至得克萨…

基于Verilog表达的FSM状态机

基于Verilog表达的FSM状态机 1 FSM1.1 Intro1.2 Why FSM?1.3 How to do 在这里聚焦基于Verilog的三段式状态机编程&#xff1b; 1 FSM 1.1 Intro 状态机是一种代码实现功能的范式&#xff1b;一切皆可状态机&#xff1b; 状态机编程四要素&#xff1a;– 1.状态State&#…

深入理解计算机系统 家庭作业6.22

每条磁道存 位 有r-xr条磁道 二者相乘就是我们要求的容量) 所以最大值x0.5

java-多态数组的多态参数

介绍 代码 employer父类 package hansunping;public class employer {private String name;private double salary;public employer(String name,double salary) {this.namename;this.salarysalary;// TODO Auto-generated constructor stub}public double getsalary() {retu…

GlusterFS企业分布式存储

GlusterFS 分布式文件系统代表-nfs常见分布式存储Gluster存储基础梳理GlusterFS 适合大文件还是小文件存储&#xff1f; 应用场景术语Trusted Storage PoolBrickVolumes Glusterfs整体工作流程-数据访问流程GlusterFS客户端访问流程 GlusterFS常用命令部署 GlusterFS 群集准备环…

职称申报总是不通过的五大原因,竟然在这里

职称评审每年都是有人通过&#xff0c;有人不能通过&#xff0c;而且有的人每年申报&#xff0c;但还是不通过&#xff0c;不通过其实都是有原因&#xff0c;抛开运气&#xff0c;有的人确实运气不好&#xff0c;不通过&#xff0c;这种没办法&#xff0c;但是大部分人申报没有…

Spring Cloud Gateway 详解:构建高效的API网关解决方案

Spring Cloud Gateway 详解&#xff1a;构建高效的API网关解决方案 Spring Cloud Gateway 是 Spring Cloud 生态系统中用于构建 API 网关的核心组件。它基于 Spring WebFlux 构建&#xff0c;旨在提供简单且有效的方式来路由和增强 API 请求。以下是 Spring Cloud Gateway 的详…

【Oracle篇】rman时间点异机恢复:从RAC环境到单机测试环境的转移(第六篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

VRRP跟踪接口及认证(华为)

#交换设备 VRRP跟踪接口及认证 一、相关概念 1.VRRP跟踪接口 当 VRRP 的 Master 设备的上行接口出现问题, 而 Master 设备一直保持 Active 状态&#xff0c;那么就会导致网络出现中断&#xff0c;所以必须要使得 VRRP 的运行状态和上行接口能够关联。在配置了 VRRP 元余的网…

经典的网站系统架构(入门级)

从开发到部署&#xff0c;从用户访问到底层数据库&#xff0c;介绍搭建网站系统的经典架构的10个核心部分。 &#xff08;图转自bytebytego&#xff0c;翻译整理by dogstar&#xff09; 1、使用Git管理和协同源代码&#xff0c;通过CI/CD或Git的Webhook方式自动同步更新部署到服…

AI赋能数据安全体系化落地,出席网安标委2024年第一次标准周“数据安全标准与能力建设研讨会”

6月13日&#xff0c;全国网络安全标准化技术委员会&#xff08;以下简称“网安标委”&#xff09;2024年第一次标准周“数据安全标准与能力建设研讨会”在南昌召开。中央网信办网络数据管理局范雪炜、工业和信息化部网络安全管理局周睿康、国家信息中心外网办安全管理处处长罗海…

红酒保存中的氧气管理:适度接触与避免过度氧化

在保存云仓酒庄雷盛红酒的过程中&#xff0c;我们不得不面对一个微妙的问题&#xff1a;氧气管理。氧气&#xff0c;这个我们生活中无处不在的气体&#xff0c;对于红酒的保存却有着至关重要的影响。适度接触氧气对红酒的陈年过程和品质维护具有积极作用&#xff0c;然而过度氧…

【APP移动端自动化测试】第四节.元素操作的API

文章目录 前言一、点击&输入&清空操作 1.1 点击元素 1.2 输入&清空元素二、获取文本内容&位置&大小操作 2.1 获取文本内容 2.2 获取位置&大小三、根据属性名获取属性值操作四、滑动和拖拽操作 4.1 _swipe 4.2 _scroll …

Threejs-12、场景的线性雾和指数雾

1、创建场景雾 //创建场景雾 scene.fog new THREE.Fog(0x999999,0.1,50);2、创建场景指数雾 scene.fog new THREE.FogExp2(0x999999,0.05);3、 设置场景背景颜色 scene.background new THREE.Color(0x999999);完整代码 <script setup> // 导入threejs import * as…

string类小贴士:让你的C++字符串处理更高效

目录 ​编辑 一、为什么要学习string类 1.1 C语言中的字符串 1.2 面试题 &#x1f333;字符串相加https://leetcode.cn/problems/add-strings/description/ 二、标准库中的string类 2.1 string类 2.2 string类的常用接口说明 1. string类对象的常见构造 2. string类对…

精准定位,智慧提纯:高级数据提取策略

在数据驱动的时代&#xff0c;高级数据提取策略成为企业决策、科学研究以及各类项目成功的关键。数据提取&#xff0c;不仅仅是简单地收集信息&#xff0c;而是需要精准定位目标数据&#xff0c;并通过智慧提纯方法&#xff0c;从海量数据中提取出有价值、有深度的信息。本文将…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第40课-实时订阅后端数据 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引…

程序员要学会偷懒--excel转建表语句

如下需求&#xff1a;一个复杂的统战系统&#xff0c;用户信息字段总共有26个sheet&#xff0c;54张小表&#xff0c;没有什么复杂的业务逻辑&#xff0c;纯增删改查。字段目测在1000个以上。建表54张。领导交待了一句这周末完成&#xff0c;我&#xff1f;&#xff1f;&#x…

【数组】【快慢双指针】删除有序数组中的重复项+移除元素+删除有序数组中的重复项II

今天趁热打铁&#xff0c;接着刷了几道标签是【数组】的题&#xff0c;基本都是双指针就能解决。 1、删除有序数组中的重复项 该题对应力扣网址 class Solution { public:int removeDuplicates(vector<int>& nums) {int i,j;int count 0;int n nums.size();nums.…