2.1 进入C++

本节将引导你编写第一个C++程序,并介绍一些基本概念。

2.1.1 main()函数

每个C++程序都必须包含一个名为 main 的函数。操作系统通过调用 main 函数来启动C++程序。main 函数是程序的入口点。

基本结构:

1
2
3
4
5
6
int main() 
{
// 程序代码

return 0; // 表示程序成功执行
}
  • int main(): 这是 main 函数的函数头。int 表示 main 函数执行完毕后将返回一个整数值给操作系统。括号 () 表示这是一个函数。
  • { ... }: 花括号标记了函数体的开始和结束。函数体包含了程序要执行的指令(语句)。
  • return 0;: 这条语句表示 main 函数执行完毕。返回值 0 通常表示程序成功执行。非零返回值通常表示程序遇到了错误。

示例:

一个最简单的C++程序:

1
2
3
4
int main() 
{
return 0;
}

这个程序什么也不做,但它是一个完整的、可以编译和运行的C++程序。

2.1.2 C++注释

注释是程序中用于解释代码的部分,它们会被编译器忽略,不会影响程序的执行。注释可以提高代码的可读性。

C++支持两种类型的注释:

  1. 单行注释:// 开始,直到该行结束。
  2. 多行注释:/* 开始,以 */ 结束,可以跨越多行。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> // 这是一个单行注释,解释包含头文件

/*
这是一个多行注释。
它可以用来写更长的解释。
下面的 main 函数是程序的入口点。
*/
int main()
{
// 使用 cout 输出 "Hello, World!" 到控制台
std::cout << "Hello, World!" << std::endl; // endl 用于换行

return 0; // 程序成功结束
}

2.1.3 C++预处理器和iostream文件

在编译C++程序之前,预处理器会首先处理源代码。预处理器指令以 # 符号开头。

#include 是一个常见的预处理器指令,它告诉预处理器将另一个文件的内容包含到当前文件中。

iostream 文件是C++标准库的一部分,包含了进行输入(input)和输出(output)操作所需的信息。例如,要使用 cout 进行输出,就需要包含 iostream 文件。

用法与示例:

1
2
3
4
5
6
7
#include <iostream> // 包含 iostream 文件,以便使用 cout

int main()
{
std::cout << "Hello from iostream!";
return 0;
}
  • #include <iostream>: 这条指令告诉预处理器查找名为 iostream 的标准头文件,并将其内容插入到该指令所在的位置。

2.1.4 头文件名

头文件(Header Files)包含了函数、类、对象等的声明,使得我们可以在程序中使用它们。C++标准库提供了许多头文件。

  • 标准库头文件: 通常使用尖括号 <> 括起来,例如 <iostream>, <cmath>, <string>。编译器会在标准库的包含路径中查找这些文件。
  • 用户自定义头文件: 通常使用双引号 "" 括起来,例如 "myheader.h"。编译器会首先在当前源文件所在的目录查找,然后在标准包含路径中查找。

C++98之前的头文件: 以前的C++头文件可能带有 .h 后缀(如 <iostream.h>)。现代C++(C++98及以后)推荐使用不带 .h 后缀的标准头文件(如 <iostream>),这些头文件的内容位于 std 命名空间中。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> // 标准库头文件
#include <cmath> // 包含数学函数,如 sqrt()
#include "myutils.h" // 用户自定义头文件 (假设存在 myutils.h)

int main() {
double num = 9.0;
double root = std::sqrt(num); // 使用 cmath 中的 sqrt 函数
std::cout << "Square root of " << num << " is " << root << std::endl;

// 假设 myutils.h 中定义了 printMessage() 函数
// printMessage("Using custom header!");

return 0;
}

2.1.5 名称空间

名称空间(Namespace)是C++中避免命名冲突的一种机制。不同的名称空间可以包含同名的函数、类或变量。

标准C++库中的所有内容(如 cout, cin, endl, string 等)都定义在名为 std 的名称空间中。

要使用 std 名称空间中的元素,有几种方法:

  1. 使用作用域解析运算符 ::: 在每个元素前加上 std::
    1
    std::cout << "Hello!" << std::endl;
  2. 使用 using 声明: 将特定的名称引入当前作用域。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <iostream>

    using std::cout; // 只引入 cout
    using std::endl; // 只引入 endl

    int main() {
    cout << "Hello!" << endl; // 不需要 std:: 前缀
    // std::cin >> variable; // 如果要用 cin,仍需 std:: 或 using std::cin;
    return 0;
    }
  3. 使用 using 编译指令: 将整个名称空间的所有名称引入当前作用域。(不推荐在头文件中或全局作用域中使用,可能导致命名冲突)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <iostream>

    using namespace std; // 引入 std 中的所有名称

    int main() {
    cout << "Hello!" << endl; // 不需要 std:: 前缀
    int x;
    cin >> x; // cin 也不需要 std:: 前缀
    return 0;
    }

推荐做法:

  • .cpp 文件的函数内部或较小作用域内,可以使用 using 声明或 using namespace std;
  • 在头文件 (.h) 中,绝对不要使用 using namespace std;,应始终使用 std:: 前缀。
  • 在简单的示例或小型项目中,using namespace std; 可以简化代码,但在大型项目中,坚持使用 std::::using 声明是更安全的做法。

2.1.6 使用cout进行C++输出

coutiostream 库中预定义的一个对象,代表标准输出流,通常连接到控制台(屏幕)。

<< 运算符(插入运算符)用于将数据发送给 cout 对象,使其显示在屏幕上。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

int main() {
// 输出字符串字面量
std::cout << "Welcome to C++!";

// 输出换行符 (使用 std::endl)
std::cout << std::endl;

// 输出数字
std::cout << "The year is ";
std::cout << 2024;
std::cout << std::endl;

// 链式输出
int age = 30;
std::cout << "My age is: " << age << " years old." << std::endl;

// 输出特殊字符 (使用转义序列)
std::cout << "This is a tab:\t." << std::endl;
std::cout << "This is a newline:\n." << std::endl;
std::cout << "This is a quote: \" " << std::endl;
std::cout << "This is a backslash: \\" << std::endl;

return 0;
}
  • std::endl: 是一个特殊的控制符(manipulator),它会输出一个换行符,并刷新输出缓冲区(确保内容立即显示)。
  • \n: 是一个转义字符,代表换行符。它只输出换行,通常不保证立即刷新缓冲区。在多数情况下,\nstd::endl 效率稍高。

2.1.7 C++源代码的格式化

C++语言对代码格式(如空格、缩进、换行)的要求相对宽松,但良好的格式化对于代码的可读性和可维护性至关重要。

基本规则和建议:

  • 语句分隔: C++使用分号 ; 来结束大多数语句。
  • 空格:
    • 通常在运算符(=, +, -, *, /, <<, >>, == 等)两边添加空格。
    • 在逗号 , 后面添加空格。
    • 在函数名和后面的括号 () 之间通常不加空格。
  • 缩进: 使用一致的缩进(通常是4个空格或一个制表符)来表示代码块(如 main 函数体、循环体、条件语句体)。这极大地提高了代码结构的可读性。
  • 换行:
    • 通常每行只写一条语句。
    • 可以在合适的地方(如运算符之后、逗号之后)将长语句分成多行。
  • 花括号 {}: 对于代码块(如函数体、if 语句块等),花括号的放置风格有多种(如 K&R 风格、Allman 风格),选择一种并保持一致即可。

示例 (良好格式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

int main()
{ // 左花括号通常独占一行或在行尾
int score = 100;
std::cout << "Initial score: " << score << std::endl;

if (score > 90)
{ // 缩进表示 if 块内部
std::cout << "Excellent!" << std::endl;
score = score + 5; // 在运算符两边加空格
} // 右花括号通常独占一行,与对应块的起始对齐

std::cout << "Final score: " << score << std::endl;

return 0;
}

示例 (不良格式,但语法正确):

1
2
#include <iostream>
int main(){int score=100;std::cout<<"Initial score: "<<score<<std::endl;if(score>90){std::cout<<"Excellent!"<<std::endl;score=score+5;}std::cout<<"Final score: "<<score<<std::endl;return 0;}

虽然第二个示例也能编译运行,但极难阅读和理解。遵循一致的、清晰的格式化风格是专业编程的重要组成部分。

2.2 C++语句

C++程序由一系列语句组成。语句是C++程序的基本执行单元,通常以分号 ; 结尾。本节将介绍两种基本的语句:声明语句和赋值语句,并进一步探讨 cout 的用法。

2.2.1 声明语句和变量

声明语句 (Declaration Statement) 用于向编译器声明程序中将要使用的变量 (Variable) 的名称和类型。

变量 是计算机内存中用于存储数据的一块区域,并且有一个名字(标识符)。通过变量名,我们可以访问和修改存储在内存中的数据。在使用变量之前,必须先声明它。

声明变量的语法:

1
typeName variableName; 
  • typeName: 指定变量要存储的数据类型(例如 int 表示整数,double 表示浮点数)。
  • variableName: 你为变量选择的名称(标识符)。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

int main()
{
// 声明一个名为 carrots 的整型变量
int carrots;

// 声明多个同类型的变量
int dogs, cats;

// 声明并同时初始化变量 (赋初值)
int fleas = 10;
double price = 99.99;

// C++11 列表初始化 (更推荐)
int hamsters = {5};
int gerbils{8}; // 花括号可以省略等号
int rats{}; // 初始化为 0

// ... 后续可以使用这些变量 ...

carrots = 25; // 赋值
std::cout << "I have " << carrots << " carrots." << std::endl;
std::cout << "Fleas: " << fleas << std::endl;
std::cout << "Hamsters: " << hamsters << std::endl;
std::cout << "Rats: " << rats << std::endl;

return 0;
}
  • 声明 (Declaration): 告诉编译器变量的名称和类型。
  • 定义 (Definition): 声明通常也是定义,因为它会为变量分配内存空间。
  • 初始化 (Initialization): 在声明变量的同时给它赋一个初始值。这是一个好习惯,可以避免使用未定义的值。

2.2.2 赋值语句

赋值语句 (Assignment Statement) 用于将一个值赋给一个变量。它使用赋值运算符 =

语法:

1
variableName = value;
  • variableName: 要接收值的变量的名称(必须是已声明的变量)。
  • value: 要赋给变量的值。这可以是一个字面常量(如 25)、另一个变量、或一个表达式的结果。

重要概念:

  • 赋值操作是将右侧的值复制到左侧的变量中。
  • 左侧必须是一个可修改的**左值 (lvalue)**,通常就是一个变量名。
  • 右侧可以是一个**右值 (rvalue)**,即一个可以产生值的表达式。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

int main()
{
int carrots; // 声明变量

carrots = 25; // 赋值语句:将 25 赋给 carrots
std::cout << "Now I have " << carrots << " carrots." << std::endl;

carrots = carrots - 1; // 赋值语句:将表达式 carrots - 1 的结果 (24) 赋给 carrots
std::cout << "Crunch, crunch. Now I have " << carrots << " carrots." << std::endl;

int dogs = 5; // 声明并初始化
int cats; // 声明

cats = dogs; // 赋值语句:将 dogs 的值 (5) 赋给 cats
std::cout << "Dogs: " << dogs << ", Cats: " << cats << std::endl;

// 可以链式赋值 (从右向左执行)
int a, b, c;
a = b = c = 10; // c=10, 然后 b=c (即 b=10), 然后 a=b (即 a=10)
std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl;

return 0;
}

2.2.3 cout的新花样

我们在 2.1.6 节已经学习了如何使用 cout 输出字符串和使用 endl 换行。cout 的一个强大之处在于它的“智能”,它可以识别并正确显示多种不同类型的数据。

cout 对象与插入运算符 << 结合使用,可以自动处理 C++ 的内置数据类型,如整数 (int)、浮点数 (double, float)、字符 (char) 以及 C 风格字符串和 std::string 对象。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string> // 包含 string 类

int main()
{
int age = 30;
double weight = 65.5;
char initial = 'J';
std::string name = "Alice"; // C++ string 对象
const char* city = "New York"; // C 风格字符串

// cout 可以自动处理不同类型
std::cout << "--- Personal Information ---" << std::endl;

// 输出整数
std::cout << "Age: "; // 输出提示信息
std::cout << age; // 输出 age 变量的值 (整数)
std::cout << std::endl; // 换行

// 输出浮点数
std::cout << "Weight: " << weight << " kg" << std::endl; // 链式输出

// 输出字符
std::cout << "Initial: " << initial << std::endl;

// 输出 C++ string 对象
std::cout << "Name: " << name << std::endl;

// 输出 C 风格字符串
std::cout << "City: " << city << std::endl;

// 混合输出
std::cout << name << " is " << age << " years old and lives in " << city << "." << std::endl;

// 输出表达式结果
std::cout << "Next year, " << name << " will be " << age + 1 << " years old." << std::endl;

return 0;
}

cout 之所以能做到这一点,是因为 << 运算符针对不同的数据类型进行了**重载 (Overloading)**(我们将在后续章节详细学习)。简单来说,就是为 << 运算符定义了多个版本,每个版本知道如何处理特定类型的数据,并将它们转换为适合输出的字符序列。

2.3 其他C++语句

本节将介绍更多C++语句,包括如何从用户那里获取输入,如何更灵活地使用 cout,并对C++的核心概念——类进行初步介绍。

2.3.1 使用cin

cout 用于输出类似,ciniostream 库中预定义的一个对象,代表标准输入流,通常连接到键盘。我们可以使用 cin 来读取用户输入的数据。

>> 运算符(提取运算符)用于从 cin 对象获取数据,并将其存储到变量中。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream> // 必须包含 iostream 以使用 cin 和 cout

int main()
{
int carrots; // 声明一个整型变量来存储输入

std::cout << "How many carrots do you have?" << std::endl; // 提示用户输入

std::cin >> carrots; // 从键盘读取一个整数,并存储到 carrots 变量中

std::cout << "Here are two more. ";
carrots = carrots + 2; // 对变量进行操作

// 输出结果
std::cout << "Now you have " << carrots << " carrots." << std::endl;

// 读取其他类型的数据
double price;
std::cout << "Enter the price per carrot: ";
std::cin >> price; // 读取一个浮点数

std::cout << "The total cost for " << carrots << " carrots is: "
<< carrots * price << std::endl;

return 0;
}
  • #include <iostream>: 使用 cin 同样需要包含此头文件。
  • std::cin: cin 对象也位于 std 名称空间中。
  • cin >> variable;: 提取运算符 >> 从输入流(键盘)中读取数据,并根据 variable 的类型进行解释,然后将值存入 variablecin 也会根据读取的数据类型自动进行转换。
  • 输入分隔: cin 通常使用空白(空格、制表符、换行符)来分隔不同的输入项。例如,如果程序期望读取两个整数 cin >> a >> b;,用户可以输入 10 20 然后按 Enter,或者输入 10 按 Enter 再输入 20 按 Enter。

2.3.2 使用cout进行拼接

我们在前面已经看到如何使用 cout 和插入运算符 << 输出单个值或字符串。cout 的一个便捷之处在于,你可以在一条语句中连续使用 << 运算符,将多个输出项“拼接”在一起。这称为**链式输出 (Chaining Output)**。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string> // 包含 string 类型

int main()
{
int age = 28;
std::string name = "Bob";
double weight = 75.3;

// 不使用拼接的写法 (多条语句)
std::cout << "Name: ";
std::cout << name;
std::cout << ", Age: ";
std::cout << age;
std::cout << ", Weight: ";
std::cout << weight;
std::cout << std::endl;

// 使用拼接的写法 (单条语句,更简洁)
std::cout << "Name: " << name
<< ", Age: " << age
<< ", Weight: " << weight
<< std::endl;

// 拼接不同类型的数据
std::cout << "In 5 years, " << name << " will be " << (age + 5) << " years old." << std::endl;

return 0;
}
  • cout << item1 << item2 << item3;: cout 对象在处理完第一个 << item1 后,会返回自身 (cout),因此可以继续处理下一个 << item2,以此类推。
  • 这种链式调用使得将变量值、字符串字面量和表达式结果组合输出变得非常方便和易读。

2.3.3 类简介

类 (Class) 是C++的核心概念,也是面向对象编程(OOP)的基础。可以把类看作是创建对象 (Object) 的蓝图或模板。

  • 封装 (Encapsulation): 类将数据(称为成员变量或属性)操作这些数据的函数(称为成员函数或方法)捆绑在一起。
  • 抽象 (Abstraction): 类提供了一个接口(通过其公有成员函数),隐藏了内部实现的复杂细节。

我们已经在使用类的对象了!coutcin 就是 C++ 标准库中定义的类的对象:

  • coutostream 类(输出流类)的一个对象。
  • cinistream 类(输入流类)的一个对象。

ostream 类定义了如何处理输出,包括 << 运算符如何针对不同数据类型工作。istream 类定义了如何处理输入,包括 >> 运算符如何读取数据。

概念理解:

想象一下 “汽车” 这个

  • 数据/属性 (成员变量): 颜色、品牌、型号、当前速度、油量等。
  • 操作/行为 (成员函数): 启动()、加速()、刹车()、鸣笛()、获取当前速度() 等。

根据这个 “汽车” 类,我们可以创建具体的对象,比如 “我的蓝色丰田卡罗拉” 或 “邻居的红色法拉利”。每个对象都有自己的属性值(不同的颜色、品牌等),但它们都共享类定义的行为(都可以启动、加速、刹车)。

示例 (概念性,非完整代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 这是一个非常简化的概念展示,不是完整的 C++ 类定义
class Car {
public: // 公有接口,外部可以访问
void startEngine(); // 成员函数声明
void accelerate(int amount);
void displayInfo();

private: // 私有数据,外部不能直接访问,只能通过成员函数
std::string color;
std::string brand;
int currentSpeed;
};

// ... 在程序的其他地方 ...
// Car myCar; // 创建一个 Car 类的对象 (需要构造函数等,此处省略)
// myCar.startEngine(); // 调用对象的成员函数
// myCar.accelerate(50);
// myCar.displayInfo();

在后续章节中,我们将深入学习如何定义和使用自己的类。目前,只需理解类是定义数据和相关操作的一种方式,而对象是类的具体实例,coutcin 就是我们已经接触到的对象实例。

2.4 函数

函数是C++程序的构建块,它们是执行特定任务的命名代码段。使用函数可以使程序模块化、更易于理解和维护。本节将介绍如何使用和定义函数。

2.4.1 使用有返回值的函数

许多C++函数会执行一个操作并返回一个值给调用它的代码。这种函数被称为**有返回值的函数 (Function with Return Value)**。

我们已经使用过一些有返回值的函数,例如 C++ 标准库 <cmath> (或 C 语言的 <math.h>) 中提供的 sqrt() 函数,它计算一个数的平方根并返回结果。

使用方法:

  1. 包含头文件: 确保包含了提供该函数声明的头文件(例如 <cmath>)。
  2. 函数调用: 使用函数名,并在括号 () 内提供所需的**参数 (Argument)**(传递给函数的值)。
  3. 处理返回值: 函数调用本身就是一个表达式,其值就是函数的返回值。可以将这个返回值赋给变量、用在更复杂的表达式中或直接输出。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cmath> // 包含 cmath 头文件以使用 sqrt() 函数

int main()
{
double area;
std::cout << "Enter the floor area, in square feet, of your home: ";
std::cin >> area; // 读取用户输入的面积

// 调用 sqrt() 函数,并将参数 area 传递给它
// 函数的返回值 (area 的平方根) 被赋给变量 side
double side = std::sqrt(area);

std::cout << "That's the equivalent of a square " << side
<< " feet to the side." << std::endl;

// 也可以直接在输出语句中使用返回值
std::cout << "The square root of 16 is: " << std::sqrt(16) << std::endl;

// 返回值可以用在表达式中
double hypotenuse = std::sqrt(3.0 * 3.0 + 4.0 * 4.0); // 计算直角三角形斜边
std::cout << "Hypotenuse of a 3-4 triangle: " << hypotenuse << std::endl;

return 0;
}
  • std::sqrt(area): 这是一个函数调用。std::sqrt 是函数名,area 是传递给函数的参数。
  • double side = ...: sqrt() 函数返回一个 double 类型的值,这个值被用来初始化 side 变量。

2.4.2 函数变体

函数可以有多种形式:

  1. 有参数,有返回值:sqrt(double x),接收一个 double 参数,返回一个 double 值。
  2. 无参数,有返回值: 例如,某些库函数可能读取系统时间并返回一个值,不需要用户提供参数。
  3. 有参数,无返回值: 这种函数执行一个操作(如打印到屏幕),但不需要返回任何计算结果。这种函数的返回类型通常声明为 void。我们将在 2.4.3 节看到例子。
  4. 无参数,无返回值: 执行一个固定的操作,不接受输入参数也不返回结果,返回类型也是 void

示例 (概念性):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <cstdlib> // 为了 rand() 和 srand()
#include <ctime> // 为了 time()

// 示例 1: 有参数,有返回值 (我们将在 2.4.4 定义自己的)
// double calculate_something(int input);

// 示例 2: 无参数,有返回值
int getRandomNumber() {
// 使用 C 标准库函数生成一个伪随机数
return std::rand() % 100; // 返回 0-99 之间的随机数
}

// 示例 3: 有参数,无返回值 (我们将在 2.4.3 定义自己的)
// void printMessage(std::string msg);

// 示例 4: 无参数,无返回值
void showStartupMessage() {
std::cout << "Program starting..." << std::endl;
std::cout << "-------------------" << std::endl;
}

int main() {
// 初始化随机数生成器 (通常只需一次)
std::srand(std::time(0));

showStartupMessage(); // 调用无参数、无返回值的函数

int randomNumber = getRandomNumber(); // 调用无参数、有返回值的函数
std::cout << "Random number: " << randomNumber << std::endl;

// 调用其他类型的函数 (假设已定义)
// printMessage("Processing data...");
// double result = calculate_something(10);
// std::cout << "Result: " << result << std::endl;

return 0;
}

2.4.3 用户定义的函数

除了使用库函数,我们还可以定义自己的函数来执行特定任务。这有助于组织代码和重用代码。

定义函数的基本结构:

1
2
3
4
5
6
returnType functionName(parameterList) 
{
// 函数体: 包含执行任务的语句
// ...
// 如果 returnType 不是 void,则需要 return 语句返回一个值
}
  • returnType: 函数执行完毕后返回的数据类型。如果函数不返回值,则使用 void
  • functionName: 你为函数选择的名称。
  • parameterList: 函数接受的参数列表,包括每个参数的类型和名称。如果没有参数,括号 () 仍然需要,但内部为空。
  • { ... }: 函数体,包含函数的代码。

函数原型 (Function Prototype):

在使用函数之前,编译器需要知道函数的接口(返回类型、名称、参数列表)。通常将函数原型放在 main() 函数之前或单独的头文件中。原型看起来像函数头,但以分号 ; 结尾,可以省略参数名。

1
returnType functionName(parameterTypeList); // 函数原型

用法与示例 (定义一个无返回值的函数):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

// 函数原型 (声明)
void cheers(int n); // 声明 cheers 函数接受一个 int 参数,无返回值

int main()
{
std::cout << "Enter an integer: ";
int count;
std::cin >> count;

cheers(count); // 函数调用:将 count 的值传递给 cheers 函数

std::cout << "Done!" << std::endl;
return 0;
}

// 函数定义
void cheers(int n) // 定义 cheers 函数,参数名为 n
{
// 函数体
for (int i = 0; i < n; i++) {
std::cout << "Cheers! ";
}
std::cout << std::endl;
// 因为返回类型是 void,所以不需要 return 语句返回值
}
  • 原型: void cheers(int n); 告诉编译器 main 函数后面会定义一个名为 cheers 的函数。
  • 调用: cheers(count); 执行 cheers 函数的代码,并将 count 的值复制给 cheers 函数的参数 n(这称为按值传递)。
  • 定义: 提供了 cheers 函数的具体实现。

2.4.4 用户定义的有返回值的函数

我们可以定义自己的函数来执行计算并返回结果。只需将 returnType 指定为期望的返回类型,并在函数体中使用 return 语句返回一个该类型的值。

用法与示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

// 函数原型: 声明 cube 函数接受一个 double 参数,返回一个 double 值
double cube(double x);

int main()
{
double side;
std::cout << "Enter the side length of a cube: ";
std::cin >> side;

double volume = cube(side); // 调用 cube 函数,将返回值赋给 volume

std::cout << "A cube with side " << side << " has a volume of "
<< volume << " cubic units." << std::endl;

// 也可以直接使用返回值
std::cout << "The cube of 2.5 is " << cube(2.5) << std::endl;

return 0;
}

// 函数定义
double cube(double x)
{
// 函数体
double result = x * x * x;
return result; // 返回计算结果 (类型必须与声明的返回类型 double 兼容)

// 或者更简洁地:
// return x * x * x;
}
  • 原型: double cube(double x); 声明了函数的接口。
  • 调用: cube(side) 调用函数,side 的值被传递给参数 x。函数执行后返回一个 double 值。
  • 定义: double cube(double x) 提供了函数的实现。return result; 将计算出的立方值返回给调用者。

2.4.5 在多函数程序中使用using编译指令

当程序包含多个函数时,每个函数都需要访问 std 名称空间中的元素(如 cout, cin, endl)。有几种处理方式:

  1. 在每个函数中都使用 std:: 前缀: 这是最安全的方式,尤其是在头文件中,但可能使代码冗长。
    1
    2
    3
    4
    5
    6
    7
    8
    void func1() {
    std::cout << "Hello from func1\n";
    }
    void func2() {
    int x;
    std::cin >> x;
    std::cout << "Input in func2: " << x << std::endl;
    }
  2. 在每个需要访问 std 的函数内部使用 using 声明或 using namespace std;: 这将 using 的作用域限制在函数内部,减少了命名冲突的风险。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <iostream>

    void func1() {
    using namespace std; // using 指令只在 func1 内部有效
    cout << "Hello from func1\n";
    }

    void func2() {
    using std::cin; // using 声明只引入 cin
    using std::cout;
    using std::endl;
    int x;
    cin >> x;
    cout << "Input in func2: " << x << endl;
    }

    int main() {
    // 在 main 中也需要访问 std
    using namespace std;
    func1();
    func2();
    cout << "Back in main." << endl;
    return 0;
    }
  3. 在所有函数定义之前(通常是在所有 #include 之后)放置一个 using namespace std; 指令: 这使得文件中的所有后续代码都可以直接使用 std 中的名称,无需 std:: 前缀。这种方式最简单,但在大型项目中或编写头文件时不推荐,因为它可能引入全局命名冲突。 对于学习和小型项目,这通常是可接受的。

用法与示例 (全局 using 指令):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <cmath>

// 将 using 指令放在所有函数之外
using namespace std;

// 函数原型
void print_sqrt(double val);
double get_input();

int main()
{
double number = get_input(); // 直接使用 get_input
print_sqrt(number); // 直接使用 print_sqrt
cout << "Program finished." << endl; // 直接使用 cout 和 endl
return 0;
}

// 函数定义
void print_sqrt(double val)
{
if (val < 0) {
cout << "Cannot calculate square root of a negative number." << endl;
} else {
double root = sqrt(val); // 直接使用 sqrt (来自 cmath, 已在 std 中)
cout << "The square root of " << val << " is " << root << endl;
}
}

double get_input()
{
double input_val;
cout << "Enter a number: "; // 直接使用 cout
cin >> input_val; // 直接使用 cin
return input_val;
}

选择哪种方式取决于项目的规模和个人/团队的编码规范。对于初学者编写的简单多函数程序,将 using namespace std; 放在 #include 之后是一种常见的简化方法。

2.5 总结

本章引导我们迈出了学习C++的第一步,涵盖了编写、编译和理解一个基本C++程序所需的 foundational concepts。

我们从C++程序的核心——main()函数开始,它是程序的入口点。了解了如何使用注释(///* */)来提高代码的可读性。接着,我们接触了C++预处理器,特别是 #include 指令,它用于包含头文件(如 <iostream>),这些头文件提供了函数和对象的声明。我们区分了标准库头文件(用 <>)和用户自定义头文件(用 "")。

名称空间的概念被引入,特别是 std 名称空间,它包含了C++标准库的大部分内容。我们学习了访问 std 中元素的三种方式:使用 std:: 前缀、using 声明和 using 编译指令,并讨论了它们的适用场景和潜在风险。

我们重点学习了如何使用 iostream 库中的 cout 对象和插入运算符 << 来显示各种类型的数据(字符串、整数、浮点数等),以及如何使用 endl\n 进行换行。代码格式化的重要性也被强调,以保证代码清晰、易于维护。

随后,我们学习了C++的基本语句类型。声明语句用于创建变量,指定其类型和名称,并可以选择在声明时进行初始化。赋值语句使用 = 运算符将值存储到变量中。我们还看到了 cout 如何智能地处理不同数据类型,以及如何通过链式调用 << 来拼接输出。

输入操作通过 cin 对象和提取运算符 >> 实现,允许程序从用户那里读取数据并存储到变量中。

最后,我们初步探讨了函数。我们学习了如何调用库函数(如 <cmath> 中的 sqrt())并使用它们的返回值。我们了解了函数的不同变体(有/无参数,有/无返回值)。更重要的是,我们学习了如何定义自己的函数,包括编写函数原型(声明)和函数定义(实现),以及如何通过函数调用来执行它们。我们还讨论了如何在包含多个函数的程序中管理 std 名称空间的使用。

通过本章的学习,我们已经能够编写简单的C++程序,实现基本的输入、处理和输出功能,并对C++程序的结构和一些核心概念有了初步的认识。

评论