《C++ Primer》导学系列:第 5 章 - 语句

2024-06-18 14:04
文章标签 c++ primer 导学 语句 系列

本文主要是介绍《C++ Primer》导学系列:第 5 章 - 语句,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

5.1 简单语句

5.1.1 基本概念

在C++中,简单语句是构成程序的基本单元。每个简单语句以分号(;)结束,可以是表达式、声明或空语句。

5.1.2 表达式语句

表达式语句是由表达式构成的语句,通常用于计算、赋值和函数调用。

示例代码
#include <iostream>int main() {int a = 10;  // 赋值表达式语句a = a + 1;  // 计算并赋值std::cout << "a: " << a << std::endl;  // 函数调用语句return 0;
}

在这个示例中,每行代码都是一个表达式语句,执行赋值、计算和输出操作。

5.1.3 声明语句

声明语句用于声明变量、函数或类型,告诉编译器它们的存在和类型信息。

示例代码
#include <iostream>int main() {int a = 10;  // 声明并初始化变量double b = 3.14;  // 声明并初始化变量std::cout << "a: " << a << ", b: " << b << std::endl;return 0;
}

在这个示例中,int adouble b是声明语句,它们声明并初始化了变量。

5.1.4 空语句

空语句仅由一个分号构成,不执行任何操作。通常用于需要语法上要求一个语句但实际不需要做任何事情的地方。

示例代码
#include <iostream>int main() {int a = 0;while (a < 10) {;  // 空语句,循环体不执行任何操作++a;}std::cout << "a: " << a << std::endl;  // 输出 a 的值return 0;
}

在这个示例中,空语句用于while循环体,但没有实际操作。

5.1.5 复合语句(块)

复合语句由一对花括号{}包围的一系列语句组成,通常用于控制语句和函数体中。复合语句可以包含声明和其他语句,是形成控制结构的基础。

示例代码
#include <iostream>int main() {int a = 0;{int b = 10;  // 复合语句中的声明a = a + b;  // 复合语句中的表达式std::cout << "Inside block: a: " << a << std::endl;}  // 复合语句的结束,b 的作用域结束std::cout << "Outside block: a: " << a << std::endl;return 0;
}

在这个示例中,复合语句(块)包含声明和表达式,块内的变量在块结束时作用域也结束。

重点与难点分析

重点

  1. 简单语句的种类和用法:理解表达式语句、声明语句和空语句的作用和用法。
  2. 复合语句的结构和作用:掌握复合语句的语法和应用场景,理解其在控制结构中的重要性。

难点

  1. 空语句的正确使用:初学者需要理解空语句的用途,避免在不适当的地方使用空语句。
  2. 复合语句中的作用域管理:掌握复合语句中变量的作用域,避免作用域混淆导致的错误。

练习题解析

  1. 练习5.1:编写一个包含多种简单语句的程序,输出结果。
  • 示例代码
#include <iostream>int main() {int x = 5;  // 声明语句x = x + 2;  // 表达式语句;  // 空语句std::cout << "x: " << x << std::endl;  // 函数调用语句return 0;
}

  1. 练习5.2:编写一个包含复合语句的程序,演示变量的作用域。
  • 示例代码
#include <iostream>int main() {int a = 10;{int b = 20;a = a + b;std::cout << "Inside block: a: " << a << ", b: " << b << std::endl;}// b 的作用域结束,下面的代码会引发错误// std::cout << "Outside block: b: " << b << std::endl;  std::cout << "Outside block: a: " << a << std::endl;return 0;
}

总结与提高

本节总结

  1. 学习了简单语句的种类,包括表达式语句、声明语句和空语句,理解了它们在程序中的作用。
  2. 掌握了复合语句的结构和应用,理解了复合语句中变量的作用域。
  3. 理解了简单语句和复合语句的基本概念和用法,通过示例代码加深了对这些概念的理解。

提高建议

  1. 多练习简单语句的使用:通过编写各种包含不同简单语句的程序,熟悉它们的用法和作用。
  2. 深入理解复合语句中的作用域管理:通过实践掌握复合语句中变量作用域的管理,避免作用域混淆导致的错误。
  3. 优化代码结构:在编写代码时,合理使用复合语句组织代码,提高代码的可读性和维护性。

5.2 语句作用域

5.2.1 基本概念

在C++中,作用域(scope)定义了标识符(如变量、函数、类型等)在程序中可见和可访问的区域。理解作用域的概念有助于避免命名冲突和不必要的错误,提高代码的可读性和可维护性。

5.2.2 作用域类型

C++中主要有以下几种作用域:

  1. 全局作用域:在整个程序中都可见和可访问的标识符。
  2. 局部作用域:在函数或复合语句(块)内定义的标识符,仅在定义它们的块内可见。
  3. 类作用域:在类或结构体内定义的标识符,仅在该类或结构体的成员函数内可见。
  4. 命名空间作用域:在命名空间内定义的标识符,仅在该命名空间内可见。

5.2.3 全局作用域

全局作用域中的标识符在整个程序中都可见,通常在文件的最外层定义。

示例代码
#include <iostream>int global_var = 100;  // 全局作用域变量void func() {std::cout << "Global variable: " << global_var << std::endl;
}int main() {std::cout << "Global variable in main: " << global_var << std::endl;func();return 0;
}

在这个示例中,global_var是一个全局作用域变量,在main函数和func函数中都可见和可访问。

5.2.4 局部作用域

局部作用域中的标识符在其定义的函数或块内可见,离开该块后不可见。

示例代码
#include <iostream>void func() {int local_var = 10;  // 局部作用域变量std::cout << "Local variable in func: " << local_var << std::endl;
}int main() {int local_var = 20;  // 局部作用域变量std::cout << "Local variable in main: " << local_var << std::endl;func();return 0;
}

在这个示例中,local_varmain函数和func函数中分别定义,并且只在各自的函数内可见。

5.2.5 类作用域

类作用域中的标识符在类或结构体的成员函数内可见。

示例代码
#include <iostream>class MyClass {
public:MyClass(int val) : member_var(val) {}void display() {std::cout << "Member variable: " << member_var << std::endl;}
private:int member_var;  // 类作用域变量
};int main() {MyClass obj(42);obj.display();return 0;
}

在这个示例中,member_var是类MyClass的成员变量,仅在类的成员函数display内可见。

5.2.6 命名空间作用域

命名空间作用域中的标识符在定义它们的命名空间内可见,可以避免全局命名冲突。

示例代码
#include <iostream>namespace MyNamespace {int var = 50;  // 命名空间作用域变量void display() {std::cout << "Namespace variable: " << var << std::endl;}
}int main() {MyNamespace::display();std::cout << "Namespace variable in main: " << MyNamespace::var << std::endl;return 0;
}

在这个示例中,vardisplay函数在命名空间MyNamespace内定义,只在该命名空间内可见。

重点与难点分析

重点:

  1. 作用域的基本概念:理解作用域的定义和作用,掌握不同类型的作用域及其应用场景。
  2. 局部和全局作用域:掌握局部和全局作用域的区别和使用方法,避免命名冲突和作用域混淆。
  3. 类作用域和命名空间作用域:理解类作用域和命名空间作用域的概念及其在实际编程中的应用。

难点

  1. 作用域管理:初学者需要通过实践理解作用域的管理,避免变量作用域混淆导致的错误。
  2. 命名空间的使用:掌握命名空间的定义和使用,特别是在大型项目中的应用,避免命名冲突。

练习题解析

  1. 练习5.3:编写一个包含全局变量和局部变量的程序,输出它们的值。
  • 示例代码
#include <iostream>int global_var = 100;  // 全局变量void func() {int local_var = 10;  // 局部变量std::cout << "Local variable in func: " << local_var << std::endl;std::cout << "Global variable in func: " << global_var << std::endl;
}int main() {int local_var = 20;  // 局部变量std::cout << "Local variable in main: " << local_var << std::endl;std::cout << "Global variable in main: " << global_var << std::endl;func();return 0;
}

  1. 练习5.4:编写一个包含类作用域变量的程序,并在类的成员函数中输出其值。
  • 示例代码
#include <iostream>class MyClass {
public:MyClass(int val) : member_var(val) {}void display() {std::cout << "Member variable: " << member_var << std::endl;}
private:int member_var;  // 类作用域变量
};int main() {MyClass obj(42);obj.display();return 0;
}

  1. 练习5.5:编写一个使用命名空间的程序,定义命名空间变量并在命名空间内的函数中输出其值。
  • 示例代码
#include <iostream>namespace MyNamespace {int var = 50;  // 命名空间变量void display() {std::cout << "Namespace variable: " << var << std::endl;}
}int main() {MyNamespace::display();std::cout << "Namespace variable in main: " << MyNamespace::var << std::endl;return 0;
}

总结与提高

本节总结

  1. 学习了作用域的基本概念,理解了作用域在程序中的作用。
  2. 掌握了全局作用域、局部作用域、类作用域和命名空间作用域的定义和使用方法。
  3. 理解了不同作用域的应用场景,通过示例代码加深了对这些概念的理解。

提高建议

  1. 多练习不同作用域的使用:通过编写各种包含不同作用域的程序,熟悉它们的用法和作用。
  2. 深入理解作用域管理:通过实践掌握作用域的管理,避免变量作用域混淆导致的错误。
  3. 优化代码结构:在编写代码时,合理使用作用域管理变量和函数,提高代码的可读性和维护性,特别是在大型项目中使用命名空间避免命名冲突。

5.3 条件语句

5.3.1 基本概念

条件语句用于根据表达式的值来控制程序的执行流程。C++中的条件语句主要包括if语句和switch语句。

5.3.2 if语句

if语句根据一个条件表达式的布尔值决定是否执行一个代码块。if语句可以有一个可选的else分支和多个else if分支。

基本语法
if (condition) {// 当 condition 为 true 时执行的代码
} else if (another_condition) {// 当 another_condition 为 true 时执行的代码
} else {// 当所有条件都不满足时执行的代码
}

示例代码
#include <iostream>int main() {int a = 10;if (a > 0) {std::cout << "a is positive" << std::endl;} else if (a == 0) {std::cout << "a is zero" << std::endl;} else {std::cout << "a is negative" << std::endl;}return 0;
}

在这个示例中,if语句检查a的值,并根据不同的条件执行不同的代码块。

5.3.3 switch语句

switch语句根据一个整数表达式的值选择要执行的代码块。每个代码块由一个或多个case标签标识,switch语句还可以包含一个可选的default标签。

基本语法
switch (expression) {case constant1:// 当 expression 等于 constant1 时执行的代码break;case constant2:// 当 expression 等于 constant2 时执行的代码break;default:// 当所有 case 都不匹配时执行的代码
}

示例代码
#include <iostream>int main() {int a = 2;switch (a) {case 1:std::cout << "a is 1" << std::endl;break;case 2:std::cout << "a is 2" << std::endl;break;case 3:std::cout << "a is 3" << std::endl;break;default:std::cout << "a is not 1, 2, or 3" << std::endl;}return 0;
}

在这个示例中,switch语句检查a的值,并根据匹配的case标签执行相应的代码块。

5.3.4 嵌套条件语句

条件语句可以嵌套使用,即在一个条件语句的代码块中包含另一个条件语句。这种嵌套结构可以处理更复杂的条件判断。

示例代码
#include <iostream>int main() {int a = 10;int b = 20;if (a > 0) {if (b > 0) {std::cout << "a and b are positive" << std::endl;} else {std::cout << "a is positive but b is not" << std::endl;}} else {std::cout << "a is not positive" << std::endl;}return 0;
}

在这个示例中,if语句嵌套在另一个if语句中,用于同时检查两个变量的值。

重点与难点分析

重点

  1. if语句的基本用法:掌握if语句的语法和用法,包括else ifelse分支的使用。
  2. switch语句的基本用法:理解switch语句的语法和用法,掌握case标签和default标签的使用。
  3. 嵌套条件语句:理解条件语句的嵌套用法,能够编写多层次的条件判断结构。

难点

  1. 条件语句的逻辑设计:初学者需要通过实践掌握条件语句的逻辑设计,确保条件判断的完整性和正确性。
  2. 避免代码重复和冗余:在使用条件语句时,应避免代码的重复和冗余,提高代码的可读性和维护性。

练习题解析

  1. 练习5.6:编写一个包含if-else语句的程序,根据用户输入的分数判断并输出相应的等级。
  • 示例代码
#include <iostream>int main() {int score;std::cout << "Enter your score: ";std::cin >> score;if (score >= 90) {std::cout << "Grade: A" << std::endl;} else if (score >= 80) {std::cout << "Grade: B" << std::endl;} else if (score >= 70) {std::cout << "Grade: C" << std::endl;} else if (score >= 60) {std::cout << "Grade: D" << std::endl;} else {std::cout << "Grade: F" << std::endl;}return 0;
}

  1. 练习5.7:编写一个包含switch语句的程序,根据用户输入的月份输出相应的季节。
  • 示例代码
#include <iostream>int main() {int month;std::cout << "Enter the month (1-12): ";std::cin >> month;switch (month) {case 12:case 1:case 2:std::cout << "Winter" << std::endl;break;case 3:case 4:case 5:std::cout << "Spring" << std::endl;break;case 6:case 7:case 8:std::cout << "Summer" << std::endl;break;case 9:case 10:case 11:std::cout << "Fall" << std::endl;break;default:std::cout << "Invalid month" << std::endl;}return 0;
}

  1. 练习5.8:编写一个嵌套if语句的程序,根据用户输入的年龄判断并输出相应的票价。
  • 示例代码
#include <iostream>int main() {int age;std::cout << "Enter your age: ";std::cin >> age;if (age < 12) {std::cout << "Ticket price: $5" << std::endl;} else {if (age < 60) {std::cout << "Ticket price: $10" << std::endl;} else {std::cout << "Ticket price: $7" << std::endl;}}return 0;
}

总结与提高

本节总结

  1. 学习了条件语句的基本概念,掌握了if语句和switch语句的语法和用法。
  2. 理解了嵌套条件语句的结构和应用,能够编写多层次的条件判断结构。
  3. 通过示例代码和练习题,加深了对条件语句的理解和应用。

提高建议

  1. 多练习条件语句的使用:通过编写各种包含条件语句的程序,熟悉if语句和switch语句的用法。
  2. 深入理解条件语句的逻辑设计:通过实践掌握条件语句的逻辑设计,确保条件判断的完整性和正确性。
  3. 优化条件语句的结构:在编写条件语句时,避免代码的重复和冗余,提高代码的可读性和维护性。

5.4 迭代语句

5.4.1 基本概念

迭代语句,也称为循环语句,用于反复执行某段代码,直到满足特定条件为止。C++提供了三种主要的迭代语句:while循环、do while循环和for循环。

5.4.2 while循环

while循环在每次迭代之前测试条件表达式,如果条件为真,则执行循环体;如果条件为假,则退出循环。

基本语法
while (condition) {// 循环体
}

示例代码
#include <iostream>int main() {int i = 0;while (i < 5) {std::cout << "i: " << i << std::endl;++i;}return 0;
}

在这个示例中,while循环打印变量i的值,直到i不再小于5。

5.4.3 do while循环

do while循环与while循环类似,但不同的是,do while循环在每次迭代之后测试条件表达式。这意味着do while循环至少执行一次。

基本语法
do {// 循环体
} while (condition);

示例代码
#include <iostream>int main() {int i = 0;do {std::cout << "i: " << i << std::endl;++i;} while (i < 5);return 0;
}

在这个示例中,do while循环确保循环体至少执行一次,即使初始条件为假。

5.4.4 for循环

for循环通常用于需要明确控制循环变量的迭代次数的情况。for循环包含初始化语句、条件表达式和迭代语句。

基本语法
for (initialization; condition; iteration) {// 循环体
}

示例代码
#include <iostream>int main() {for (int i = 0; i < 5; ++i) {std::cout << "i: " << i << std::endl;}return 0;
}

在这个示例中,for循环打印变量i的值,从0到4。

5.4.5 范围for语句

C++11引入了范围for语句(range-based for loop),用于遍历数组或其他容器。范围for语句使代码更加简洁和可读。

基本语法
for (declaration : expression) {// 循环体
}
  • declaration是用于引用容器元素的变量声明。
  • expression是一个可迭代的容器或范围。

示例代码
#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};for (int value : vec) {std::cout << "value: " << value << std::endl;}return 0;
}

在这个示例中,范围for循环遍历vec中的每个元素,并输出其值。

重点与难点分析

重点

  1. while循环和do while循环:掌握while循环和do while循环的基本语法和用法,理解它们的区别。
  2. for循环:理解for循环的基本语法,掌握初始化语句、条件表达式和迭代语句的作用。
  3. 范围for语句:掌握范围for语句的用法,理解其在遍历容器中的优势。

难点

  1. 循环控制:初学者需要通过实践掌握循环控制,包括循环的初始化、条件判断和迭代更新。
  2. 范围for语句的应用:熟悉范围for语句的语法和应用场景,特别是在处理标准库容器时的应用。

练习题解析

  1. 练习5.9:编写一个while循环,计算并输出1到10的和。
  • 示例代码
#include <iostream>int main() {int sum = 0;int i = 1;while (i <= 10) {sum += i;++i;}std::cout << "Sum: " << sum << std::endl;return 0;
}

  1. 练习5.10:编写一个do while循环,反复读取用户输入,直到输入0为止。
  • 示例代码
#include <iostream>int main() {int number;do {std::cout << "Enter a number (0 to exit): ";std::cin >> number;} while (number != 0);std::cout << "Goodbye!" << std::endl;return 0;
}

  1. 练习5.11:编写一个for循环,输出1到10的平方。
  • 示例代码
#include <iostream>int main() {for (int i = 1; i <= 10; ++i) {std::cout << "Square of " << i << " is " << i * i << std::endl;}return 0;
}

  1. 练习5.12:编写一个使用范围for语句的程序,输出数组中的每个元素。
  • 示例代码
#include <iostream>int main() {int arr[] = {1, 2, 3, 4, 5};for (int value : arr) {std::cout << "value: " << value << std::endl;}return 0;
}

总结与提高

本节总结

  1. 学习了迭代语句的基本概念,掌握了while循环、do while循环和for循环的语法和用法。
  2. 理解了范围for语句的结构和应用,能够使用范围for语句遍历数组和标准库容器。
  3. 通过示例代码和练习题,加深了对迭代语句的理解和应用。

提高建议

  1. 多练习迭代语句的使用:通过编写各种包含迭代语句的程序,熟悉while循环、do while循环、for循环和范围for语句的用法。
  2. 深入理解循环控制:通过实践掌握循环的初始化、条件判断和迭代更新,确保循环的正确执行。
  3. 优化循环的效率:在编写循环时,注意循环的效率和性能,避免不必要的计算和重复操作,提高代码的执行效率。

5.5 跳转语句

5.5.1 基本概念

跳转语句用于在程序中改变控制流,直接跳转到程序的另一个部分。C++中的主要跳转语句包括breakcontinuegotoreturn和异常处理相关的throw

5.5.2 break语句

break语句用于立即终止所在的循环或switch语句,并跳转到紧接着循环或switch语句后的语句。

示例代码
#include <iostream>int main() {for (int i = 0; i < 10; ++i) {if (i == 5) {break;  // 当 i 等于 5 时,跳出循环}std::cout << "i: " << i << std::endl;}std::cout << "Loop ended." << std::endl;return 0;
}

在这个示例中,当i等于5时,break语句终止for循环。

5.5.3 continue语句

continue语句用于跳过当前循环迭代的剩余部分,并继续执行下一次循环迭代。

示例代码
#include <iostream>int main() {for (int i = 0; i < 10; ++i) {if (i % 2 == 0) {continue;  // 跳过偶数}std::cout << "i: " << i << std::endl;}return 0;
}

在这个示例中,continue语句跳过偶数的输出,只输出奇数。

5.5.4 goto语句

goto语句用于无条件跳转到程序中的指定标签。尽管goto语句很强大,但滥用会导致代码难以阅读和维护,因此通常应避免使用。

示例代码
#include <iostream>int main() {int i = 0;start:std::cout << "i: " << i << std::endl;++i;if (i < 5) {goto start;  // 跳转到标签 start}return 0;
}

在这个示例中,goto语句跳转到标签start,实现了一个简单的循环。

5.5.5 return语句

return语句用于终止函数的执行,并将控制权返回给调用函数。return语句可以带有一个返回值,该值将作为函数调用的结果。

示例代码
#include <iostream>int add(int a, int b) {return a + b;  // 返回两个整数的和
}int main() {int result = add(5, 3);std::cout << "Result: " << result << std::endl;return 0;
}

在这个示例中,return语句将add函数的结果返回给调用者。

5.5.6 throw语句

throw语句用于抛出一个异常,使程序跳转到最近的异常处理器。异常处理在第18章详细讨论,这里只作简单介绍。

示例代码
#include <iostream>
#include <stdexcept>int main() {try {throw std::runtime_error("An error occurred");  // 抛出异常} catch (const std::runtime_error& e) {std::cout << "Caught exception: " << e.what() << std::endl;}return 0;
}

在这个示例中,throw语句抛出一个std::runtime_error异常,并在catch块中捕获和处理。

重点与难点分析

重点

  1. break和continue语句:掌握breakcontinue语句的基本用法,理解它们在循环中的作用。
  2. goto语句:了解goto语句的用法和潜在问题,避免滥用。
  3. return语句:理解return语句的基本用法,掌握其在函数中的作用。
  4. throw语句:初步了解throw语句的用法,理解其在异常处理中的作用。

难点

  1. 跳转控制:初学者需要通过实践掌握不同跳转语句的控制流,理解它们在程序中的具体应用场景。
  2. 异常处理:虽然throw语句在本章只是简单介绍,但理解其在异常处理中的作用是一个难点,需要在后续章节中深入学习。

练习题解析

  1. 练习5.13:编写一个程序,使用break语句终止循环。
  • 示例代码
#include <iostream>int main() {for (int i = 0; i < 10; ++i) {if (i == 7) {break;  // 当 i 等于 7 时,跳出循环}std::cout << "i: " << i << std::endl;}std::cout << "Loop ended." << std::endl;return 0;
}

  1. 练习5.14:编写一个程序,使用continue语句跳过循环中的某些迭代。
  • 示例代码
#include <iostream>int main() {for (int i = 0; i < 10; ++i) {if (i % 3 == 0) {continue;  // 跳过能被 3 整除的数字}std::cout << "i: " << i << std::endl;}return 0;
}

  1. 练习5.15:编写一个程序,使用goto语句实现循环,并注意避免滥用。
  • 示例代码
#include <iostream>int main() {int i = 0;start:std::cout << "i: " << i << std::endl;++i;if (i < 5) {goto start;  // 跳转到标签 start}return 0;
}

  1. 练习5.16:编写一个包含return语句的函数,并调用该函数输出其返回值。
  • 示例代码
#include <iostream>int multiply(int a, int b) {return a * b;  // 返回两个整数的乘积
}int main() {int result = multiply(4, 5);std::cout << "Result: " << result << std::endl;return 0;
}

  1. 练习5.17:编写一个程序,使用throw语句抛出一个异常,并在catch块中处理该异常。
  • 示例代码
#include <iostream>
#include <stdexcept>int main() {try {throw std::runtime_error("An error occurred");  // 抛出异常} catch (const std::runtime_error& e) {std::cout << "Caught exception: " << e.what() << std::endl;}return 0;
}

总结与提高

本节总结

  1. 学习了跳转语句的基本概念,掌握了breakcontinuegotoreturnthrow语句的用法。
  2. 理解了跳转语句在控制程序流中的作用,并通过示例代码加深了对这些概念的理解。
  3. 初步了解了异常处理中的throw语句,理解其在异常处理中的作用。

提高建议

  1. 多练习跳转语句的使用:通过编写各种包含跳转语句的程序,熟悉breakcontinuegotoreturnthrow语句的用法。
  2. 深入理解跳转控制:通过实践掌握跳转语句的控制流,理解它们在程序中的具体应用场景。
  3. 避免滥用goto语句:在编写代码时,应尽量避免使用goto语句,以提高代码的可读性和维护性。
  4. 学习异常处理:后续章节中将深入学习异常处理,掌握throw语句及其相关的异常处理机制。

5.6 try语句块和异常处理

5.6.1 基本概念

异常处理是C++中用于应对程序运行过程中出现的错误情况的一种机制。通过异常处理,可以将错误与正常的代码逻辑分开,使程序更加健壮和易于维护。异常处理的核心机制包括try语句块、throw语句和catch语句。

5.6.2 try语句块

try语句块用于包围可能引发异常的代码。当try语句块中的代码抛出异常时,程序控制流将转移到相应的catch块中。

基本语法
try {// 可能引发异常的代码
} catch (exceptionType1 e1) {// 处理 exceptionType1 类型的异常
} catch (exceptionType2 e2) {// 处理 exceptionType2 类型的异常
}

5.6.3 throw语句

throw语句用于抛出一个异常,使程序跳转到最近的匹配catch块。throw语句可以抛出任意类型的对象,但通常抛出派生自std::exception的异常对象。

基本语法
throw exceptionObject;

示例代码
#include <iostream>
#include <stdexcept>int divide(int a, int b) {if (b == 0) {throw std::runtime_error("Division by zero");  // 抛出异常}return a / b;
}int main() {try {int result = divide(10, 0);std::cout << "Result: " << result << std::endl;} catch (const std::runtime_error& e) {std::cout << "Caught exception: " << e.what() << std::endl;}return 0;
}

在这个示例中,divide函数在除数为零时抛出std::runtime_error异常,并在main函数中捕获和处理该异常。

5.6.4 catch语句

catch语句用于捕获由try块抛出的异常,并执行处理代码。一个try块可以有多个catch块,每个catch块处理不同类型的异常。

基本语法
catch (exceptionType e) {// 处理异常的代码
}

示例代码
#include <iostream>
#include <stdexcept>int main() {try {throw std::runtime_error("An error occurred");} catch (const std::runtime_error& e) {std::cout << "Caught exception: " << e.what() << std::endl;} catch (const std::exception& e) {std::cout << "Caught general exception: " << e.what() << std::endl;}return 0;
}

在这个示例中,catch块捕获并处理std::runtime_error异常和其他std::exception类型的异常。

5.6.5 标准异常类

C++标准库提供了一些常用的异常类,这些类派生自std::exception。常见的标准异常类包括:

  • std::runtime_error
  • std::logic_error
  • std::out_of_range
  • std::invalid_argument
  • std::bad_alloc

示例代码
#include <iostream>
#include <stdexcept>void checkIndex(int index, int size) {if (index < 0 || index >= size) {throw std::out_of_range("Index out of range");}
}int main() {try {checkIndex(10, 5);} catch (const std::out_of_range& e) {std::cout << "Caught exception: " << e.what() << std::endl;}return 0;
}

在这个示例中,checkIndex函数在索引超出范围时抛出std::out_of_range异常,并在main函数中捕获和处理该异常。

重点与难点分析

重点

  1. 异常处理的基本概念:理解trythrowcatch语句的基本概念和用法。
  2. 标准异常类的使用:掌握常见的标准异常类及其应用场景。

难点

  1. 异常的传播和捕获:初学者需要通过实践理解异常的传播机制及如何正确捕获和处理异常。
  2. 自定义异常类:在复杂项目中,自定义异常类可以提高代码的可读性和可维护性,需要掌握自定义异常类的方法。

练习题解析

  1. 练习5.18:编写一个函数,抛出一个标准异常,并在main函数中捕获并处理该异常。
  • 示例代码
#include <iostream>
#include <stdexcept>void func() {throw std::runtime_error("An error occurred in func");
}int main() {try {func();} catch (const std::runtime_error& e) {std::cout << "Caught exception: " << e.what() << std::endl;}return 0;
}

  1. 练习5.19:编写一个包含多个catch块的程序,捕获不同类型的异常。
  • 示例代码
#include <iostream>
#include <stdexcept>int main() {try {throw std::out_of_range("Out of range error");} catch (const std::out_of_range& e) {std::cout << "Caught out_of_range exception: " << e.what() << std::endl;} catch (const std::exception& e) {std::cout << "Caught general exception: " << e.what() << std::endl;}return 0;
}

  1. 练习5.20:编写一个函数,使用throw语句抛出一个自定义异常类,并在main函数中捕获并处理该异常。
  • 示例代码
#include <iostream>
#include <stdexcept>class MyException : public std::exception {
public:const char* what() const noexcept override {return "My custom exception";}
};void func() {throw MyException();
}int main() {try {func();} catch (const MyException& e) {std::cout << "Caught MyException: " << e.what() << std::endl;} catch (const std::exception& e) {std::cout << "Caught general exception: " << e.what() << std::endl;}return 0;
}

总结与提高

本节总结

  1. 学习了异常处理的基本概念,掌握了trythrowcatch语句的用法。
  2. 理解了标准异常类的应用场景,并通过示例代码加深了对这些概念的理解。
  3. 掌握了异常的传播机制及其在程序中的具体应用。

提高建议

  1. 多练习异常处理的使用:通过编写各种包含异常处理的程序,熟悉trythrowcatch语句的用法。
  2. 深入理解异常的传播和捕获:通过实践掌握异常的传播机制及其在程序中的具体应用,确保异常能够被正确捕获和处理。
  3. 自定义异常类:在复杂项目中,自定义异常类可以提高代码的可读性和可维护性,掌握自定义异常类的方法。

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

这篇关于《C++ Primer》导学系列:第 5 章 - 语句的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072194

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

JavaWeb系列二十: jQuery的DOM操作 下

jQuery的DOM操作 CSS-DOM操作多选框案例页面加载完毕触发方法作业布置jQuery获取选中复选框的值jQuery控制checkbox被选中jQuery控制(全选/全不选/反选)jQuery动态添加删除用户 CSS-DOM操作 获取和设置元素的样式属性: css()获取和设置元素透明度: opacity属性获取和设置元素高度, 宽度: height(), widt

C语言入门系列:探秘二级指针与多级指针的奇妙世界

文章目录 一,指针的回忆杀1,指针的概念2,指针的声明和赋值3,指针的使用3.1 直接给指针变量赋值3.2 通过*运算符读写指针指向的内存3.2.1 读3.2.2 写 二,二级指针详解1,定义2,示例说明3,二级指针与一级指针、普通变量的关系3.1,与一级指针的关系3.2,与普通变量的关系,示例说明 4,二级指针的常见用途5,二级指针扩展到多级指针 小结 C语言的学习之旅中,二级