附录 C
通过示例
本C++ 编程书籍的附录将尝试为用户提供对C++ 编程语言的补充实践理解。它将是一个依赖于C++ 编程书籍中已经介绍的课程和理论内容的聚合,因此为了始终如一地列出主书中使用的所有可编译示例程序,本附录将有助于以实践的方式刷新你的知识,保证性能并允许更容易地维护使用的代码和测试示例的派生。
这是一项开放的工作,如果你发现术语或概念有任何问题,你可以通过贡献来帮助它,你的参与是必需的,也是受欢迎的! 你也可以自由地陈述对实际书籍内容、结构或其他概念事项的任何偏好、缺点或愿景,请参阅此 Wikibook 的讨论页面以获取参与的正确论坛。
此C++ 编程 Wikibook页面正在建设中。 它可能不完整或包含错误。请参阅Talk:C++ 编程/内容以进行讨论。 |
前言
通过示例学习 C++ 编程可以用作学习该语言的另一种方法,通过将实践置于理论之上。在任何情况下,这都需要你具备更高的专业知识水平。你需要了解 C++ 文件是如何组织的,拥有并知道如何操作编译器,以及了解在代码中不可见的某些细微差别。请理解,你将能够在某种程度上阅读和用 C++ 编程,但要真正理解该语言,不仅需要实践,还需要理论。如有疑问,请随时参考主书。
在本书中,我们介绍了在哪里获取编译器(参见编译器部分),这将为你提供继续所需的工具。如果你没有、不想或不需要在你的机器上安装编译器,你可以使用一个可在http://ideone.com(或http://codepad.org,但你必须更改代码以不依赖交互式输入)获得的免费 WEB 编译器。
第 1 章: C++ 一种多范式语言
- 这是本书的初始章节,它试图向读者介绍 C++ 语言,谈论语言的历史及其演变,提供概述,试图传达人们应该了解该语言的原因。
- 要理解 C++,首先必须确定什么是编程语言,它们如何相互关联(低级/高级),不同的编程范式,过程式编程和面向对象编程(对象和类、封装、继承、多重继承、多态)、泛型编程等。作为一种允许,不仅提供一些有用的背景,而且对于有其他语言经验的读者来说,能够理解与其他密切相关的语言相比,C++ 的特殊之处(C(C++ 的起源)、Java、C#、(C++/CLI)和 D)。
- 在本章中,读者被要求检查第一个 C++ 源代码,常见的Hello World,并提供资源以逐步了解它。
Hello World - 编写、编译和运行 C++ 程序
下面是一个简单的 C++ 程序示例
// 'Hello World!' program
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
编写程序时,会使用开发环境。你的开发环境可以是基本的文本编辑器,也可以是功能丰富的 C++ 集成开发环境 (IDE)。你不应该使用像 Microsoft Word 这样的文字处理器,因为它会向文本添加格式化代码。
如果还没有可用的编译器,请参阅本书的在哪里获取编译器部分。
打开你的开发环境,输入显示的程序(或复制粘贴),并将其另存为hello.cc。
现在使用 C++ 编译器编译它
COMMAND_PROMPT> g++ hello.cc -o hello
此示例使用 GCC,即 GNU 编译器集合(http://gcc.gnu.org),但你可以使用任何其他编译器,或使用 IDE 进行编译。上述命令将生成一个名为hello或hello.exe的可执行文件。调用可执行文件以运行你的第一个 C++ 程序
Unix
COMMAND_PROMPT> ./hello Hello World! COMMAND_PROMPT>
Microsoft Windows
COMMAND_PROMPT> dear hello Hello World! COMMAND_PROMPT>
斜体文本由你键入,粗体文本由程序输出。如果你使用IDE,它可能会根据语法自动为你着色代码。
故障排除
- g++
- 命令未找到
你没有安装 GNU C++ 编译器。如果你有其他编译器,请查看其文档以获取正确的编译命令。
- 错误的编译器命令
很多奇怪的错误,多次提及
undefined reference to `std::basic_ostream' [..]
通常以以下结尾
collect2: ld returned 1 exit status
要使用g++编译你的 hello.cc,请使用
g++ hello.cc -o hello
对于gcc,请使用
gcc hello.cc -o hello -lstdc++
- hello
- 命令未找到
你没有键入完整路径,请尝试
./hello
是否存在hello此目录中的程序?当你键入时,你能看到它吗?ls?如果不是,则你的编译(g++ hello.cc -o hello)失败或你已更改到错误的目录。
如果你未指定-o hello, g++命名输出文件a.out(汇编程序输出),出于历史原因。在这种情况下,请键入
./a.out
以执行程序。
解释你的第一个 C++ 程序
预处理指令
C++ 的一些特性是语言的一部分,而另一些特性是标准库的一部分。标准库是每个符合标准的 C++ 编译器都提供的代码体。当 C++ 编译器编译你的程序时,通常也会将其与标准 C++ 库链接。
当你使用库中的特性时,C++ 要求你声明将要使用的特性。程序中的第一行是一个预处理指令。在我们的示例中,它显示为粗体和斜体
- IOStreams 的预处理指令
#include <iostream>
此行导致 C++ 声明位于
iostream 头文件,需要在程序中包含它。通常,编译器会将名为iostream的头文件的内容插入到程序中。它插入的位置取决于系统。此类文件的位置可能在编译器的文档中有所描述。标准 C++ 头文件的列表在标准头文件参考表中。该iostream头文件包含用于输入/输出 (I/O) 的各种声明。它使用称为流的 I/O 机制的抽象。例如,有一个名为std::cout的输出流对象,用于将文本输出到标准输出。通常,这会将文本显示在计算机屏幕上。
预处理器是编译器的一部分,它在实际编译器看到代码之前对代码进行一些转换。例如,在遇到#include <iostream>指令时,它会用iostream头文件的内容替换该指令。
main函数
int main()
{
// ...
}
以上几行表示一段 C++ 代码块,名为main。这样的命名代码块在 C++ 中称为函数。代码块的内容称为函数的主体。
单词int以粗体显示,因为它是一个关键字。C++ 关键字具有一些特殊含义,并且也是保留字,即不能用于除了其预期用途之外的任何其他用途。另一方面main不是关键字,您可以在许多关键字无法使用的地方使用它(尽管不建议这样做,因为可能会导致混淆)。
每个(符合标准的)C++ 程序都必须定义一个名为main的函数。程序的执行从此处开始。正如我们稍后将看到的,main可能会调用其他函数,而这些函数又可能调用其他函数。编译器会安排在程序开始执行时调用main函数。(虽然这通常是正确的,但并非总是如此。有一个例外是main并非总是在一开始就被执行,我们稍后会看到。)
现在让我们看看main函数内部的代码。
打印 Hello World!
在main中,第一行使用std::cout对象打印字符串(字符序列)Hello World!并在行尾添加换行符。
std::cout << "Hello World!\n";
这一行是C++ 语句。C++ 语句以分号 (;) 结尾。在语句<<中,称为插入运算符,用于使用std::cout流输出字符串。C++ 字符串用双引号 (") 括起来。引号本身不是字符串的一部分,因此不会被打印。序列\n在字符串中用于指示当前行的结尾。虽然该序列由两个字符表示,但它只占用一个字符的内存空间。因此,序列\n称为换行符。换行的实际过程取决于系统,但 C++ 标准库会为您处理,您无需关心。
对上述程序的修改
以下是同一个程序,进行了少量修改
// This program just displays a string and exits
#include <iostream>
int main()
{
std::cout << "Hello World!";
std::cout << std::endl;
return 0;
}
注释
开头添加的行
// This program just displays a string and exits
是一个注释,试图解释代码的作用。注释对于任何非平凡的程序都是必不可少的,这样阅读代码的人才能理解它预期做什么。注释分隔符之间包含的内容没有限制。编译器只是忽略注释中的所有内容。在我们的示例中,注释以斜体显示。C++ 支持两种形式的注释
- 单行注释以//开头,一直延伸到行尾。这些也可以用于语句的右侧,以解释该语句的作用。
- 多行注释以/*序列开头,以*/序列结尾。这些可用于跨越多行的注释。这些也称为 C 样式注释,因为这最初是 C 中唯一可用的注释类型。例如:
/* This program displays a string and then it exits */
有时注释也用于括起我们暂时希望编译器忽略但打算以后使用的代码。这在调试(查找程序中的错误或错误的过程)中非常有用。如果程序没有给出预期的结果,可以通过“注释掉”代码来跟踪哪个特定的语句存在错误。由于 C 样式注释可以在行尾之前停止,因此这些可以用于“注释掉”程序中一行内的少量代码。
刷新输出流缓冲区
每当您写入(即发送任何输出)到输出流时,它不会立即被写入。它首先存储在内存中,实际上可能会在将来的任何时间写入。此过程称为缓冲,用于存储此类临时数据的内存区域称为缓冲区。有时需要刷新输出流缓冲区以确保所有数据都已写入。这是通过将插入运算符应用于输出流和对象std::endl来实现的。这就是
std::cout << std::endl;
行所做的操作。在刷新缓冲区之前,std::endl
还会写入一个换行符(这解释了它的名称,end line)。因此,在上一行打印的字符串中省略了换行符。
返回成功代码
在大多数操作系统中,每个程序都允许使用称为退出状态的值与调用方通信,以表明它是否已成功完成执行。按照约定,退出状态为 0 表示成功,任何其他值表示失败。不同的退出状态值可用于指示不同类型的失败。在我们的简单程序中,我们希望以状态 0 退出。mainC++ 允许
return 0;
函数返回一个整数,该整数将作为程序的退出状态传递给操作系统。语句main使main返回 0。由于int函数需要返回一个整数,因此使用关键字main开始函数定义。此语句是可选的,因为编译器会自动生成代码以在控制流出函数而没有return语句的情况下为main函数返回 0。这就是为什么第一个程序无需任何 return 语句就能工作的原因。请注意,这只是一个特殊情况,仅适用于
函数。对于其他函数,如果声明它们返回任何内容,则必须返回一个值。return常见编程错误 1 虽然main语句是可选的,但不应声明为返回void
(声明为void的函数是不返回任何内容的函数),就像在 Java 等其他语言中一样。一些 C++ 编译器可能不会对此发出抱怨,但这是错误的。这样做可能相当于返回存储在特定内存位置或寄存器中的任何随机数,具体取决于平台。此做法也可能对某些操作系统造成潜在损害,这些操作系统依靠返回代码来确定如何处理崩溃或其他异常退出。
空白和缩进
// This program just displays a string and exits, variation 1
#include <iostream>
int main() { std::cout<<"Hello World!"; std::cout<<std::endl; return 0; }
空格、制表符和换行符(换行符)通常称为空白。除了预处理指令和 C++ 样式注释在换行符处结束的规则外,这些都被编译器忽略,除非在引号内。因此,上述程序也可以写成如下形式
但是,请注意,空格是必需的,用于分隔相邻的单词和数字。为了使程序更易读,必须适当地使用空白。
// This program just displays a string and exits, variation 2
#include <iostream>
int main() {
std::cout << "Hello World!";
std::cout << std::endl;
return 0;
}
使用空白来提高代码可读性的约定构成了缩进风格。例如,使用其他缩进风格,程序可以这样编写
// This program just displays a string and exits
#include <iostream>
int main()
{
std::cout << "Hello World!";
std::cout << std::endl;
return 0;
}
或者这样
第 1 章:可编译示例
Hello World - 显示字符串 - 显示字符串1 - 显示字符串2
数据和变量
变量
// This program adds two numbers and prints their sum.
#include <iostream>
int main()
{
int a;
int b;
int sum;
sum = a + b;
std::cout << "The sum of " << a << " and " << b << " is " << sum << "\n";
return 0;
}
// This program adds two numbers and prints their sum, variation 1
#include <iostream>
#include <ostream>
using namespace std;
int main()
{
int a = 123, b (456), sum = a + b;
cout << "The sum of " << a << " and " << b << " is " << sum << endl;
return 0;
}
将两个数字相加并打印它们的和
初学者程序员需要理解如何编写一个对三个整数进行排序的程序。如果您想将其应用于稍后要纳入现实生活情境的程序,这将非常有用。我使用此代码来展示如何在工作中应用此代码。
例如,如果您正在统计人员,例如 (1) 某个地区的居民密度或 (2) 员工人数以获取人口统计数据。例如,如果您在人口普查局工作,并且想要衡量有多少人从乡村搬到城市,您可能需要对这些数字进行排序。如果您想知道申请某项工作的女性人数是否多于男性,您将需要对这些整数进行排序。有时,此类排序函数可以在过滤并以从最大整数降序到最小整数的视图显示的网站上看到。在用户界面 (UI) 的背后,当用户单击网站上的提交按钮时,会调用一个排序函数。
#include <iostream>
#include <cmath>
using namespace std;
void sortNums(int& input1, int& input2, int& input3);
int main()
{
int x, y, z; // create variables
// Get numbers using cout and cin
cout << "Please enter 3 numbers." << endl;
cin >> x;
cin >> y;
cin >> z;
// Sort numbers: x, y, and z
sortNums(x, y, z); // calls the function titled sortNums
cout << x << ", " << y << ", " << z << endl; // outputs the numbers
return 0;
}
void sortNums(int &myNumA, int &myNumB, int &myNumC) // sort numbers
{
int temp; // create temp variable
if (myNumA > myNumB)
{
temp = myNumA;
myNumA = myNumB;
myNumB = temp;
}
if (myNumB > myNumC)
{
temp = myNumB;
myNumB = myNumC;
myNumC = temp;
}
if (myNumA > myNumB)
{
temp = myNumA;
myNumA = myNumB;
myNumB = temp;
}
}
此示例获取 3 个整数(来自用户的输入)并对其进行排序。本节的主要目的是展示如何在现实生活情境中使用简单的代码。
第 3 章:面向对象编程
第 4 章:高级功能
// very simple C++ program using a class.
#include <iostream>
class myClass
{
public:
myClass(int);
private:
int i;
};
myClass::myClass(int x) : i(x) {}
int main()
{
myClass my_class(5);
// dynamic
myClass* my_class_ptr = new myClass(5);
delete my_class_ptr;
return 0;
}
I/O 流
// This program just displays a string and exits
#include <iostream>
int main()
{
std::cout << "Hello World!";
std::cout << std::endl;
return 0;
}
// This program just displays a string and exits, variation 1
#include <iostream>
int main() { std::cout<<"Hello World!"; std::cout<<std::endl; return 0; }
// This program just displays a string and exits, variation 2
#include <iostream>
int main() {
std::cout << "Hello World!";
std::cout << std::endl;
return 0;
}