Skip to content

第 1 章 开始

1.1 一个简单的 C++ 程序

>> 概念:函数

函数的定义将包含 4 个部分:返回类型(return type函数名(function name一个括号包围的形参列表(parameter list)以及函数体(function body

一个程序将包含多个函数,其中 main 函数将会被系统主动调用来执行程序功能。

NOTE

main 函数的返回类型必须是 int,即整数类型

1.2 输入 & 输出

C++ 并未定义任何输入输出语句,但是其包含的全面的标准库提供了 IO 机制。

例如 iostream 库,其包含 istream 输入流与 ostream 输出流。

>> 概念:流

流就是一个字符序列,从 IO 设备读出或写入 IO 设备的,流(stream)想表达的意思是:随着时间的推移,字符是顺序生成或消耗的。

标准库中提供了 4 个输入输出对象:cin、cout、cerr 与 clog

通常使用 cerr 来输出警告信息,而 clog 来输出程序运行时的一般性信息。

1.2.1 向流写入数据

c++
#include <iostream>

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

从本质上理解,cout 作为一个 IO 对象,其后应该是一个表达式,而这个表达式用到了 << 输出运算符<< 运算符接受两个对象,一个是左边的 ostream 对象,另一个是右边的待打印对象,并且返回左侧的 ostream 对象<< 运算符从左到右依次执行,来依次打印每一个输出对象,直到最后剩下一个单独的 ostream 对象,因此,上述代码等价于:

c++
#include <iostream>

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

1.2.2 从流读取数据

c++
#include <iostream>
int a, b;
int main() {
    std::cout << "Enter two numbers:" << endl;
    std::cin >> a >> b;
    return 0;
}

cin 是另一个 IO 对象,用于接收 istream 输入流,同时我们用到了 >> 输入运算符,他从左侧接受一个 istream 对象,并存入右侧对象中。

1.3 注释

c++
#include <iostream>
int a, b;
int main() {
    std::cout << "Enter two numbers:" << endl;
    // 输出提示
    std::cin >> a >> b;
    /*输入参数*/
    return 0;
}

C++ 支持两种注释语句:// 行内注释/**/ 跨行注释

跨行注释不可嵌套。

NOTE

编译器会忽略注释,但是开发人员不会,并且会倾向于相信其正确性,所以请及时为你的程序加上或更新注释,记住:没有注释的程序已经够糟糕了,但错误 / 过时的注释比完全没有注释更糟糕!

1.4 命名空间

1.4.1 名字空间的定义

名字空间是 C++ 提供的一个用于防止命名冲突的机制。通过名字空间,可以将不同作用域中的同名实体(如变量、函数、类等)区分开来,避免不同库或模块中的相同名称互相冲突。

C++
namespace myNamespace {
int num = 42;
void display() { std::cout << "Hello from myNamespace!" << std::endl; }
} // namespace myNamespace

在这个例子中,num 变量和 display 函数都属于 myNamespace 命名空间。

1.4.2 使用名字空间中的成员

要使用某个名字空间中的变量或函数,可以通过作用域运算符:: 进行限定。

例子

cpp
std::cout << myNamespace::num << std::endl; // 输出:42
myNamespace::display(); // 输出:Hello from myNamespace!

1.4.3 using 声明

如果频繁使用某个名字空间中的单个成员,可以使用 using 声明,将特定名字空间中的成员引入当前作用域,以简化代码。

cpp
using myNamespace::num;
std::cout << num << std::endl; // 输出:42

使用 using 声明后,直接使用 num 即可,而不需要写 myNamespace::num

1.4.4 using 指令

using namespace 指令可以将整个名字空间引入当前作用域,从而不需要再对每个成员使用限定符。不过,这样做可能会导致名字冲突

cpp
using namespace myNamespace;
std::cout << num << std::endl; // 输出:42
display();                     // 输出:Hello from myNamespace!

1.4.5 标准库的名字空间

C++ 标准库中的所有内容都在 std 命名空间中。因此,在使用标准库的任何对象时,通常需要加上 std:: 前缀,例如 std::coutstd::string 等。

cpp
std::cout << "Hello, World!" << std::endl;
std::string str = "C++ Primer";

1.4.6 名字空间的嵌套

名字空间可以嵌套定义,从而形成分层的作用域结构。

cpp
cpp复制代码namespace outer {
    namespace inner {
    int value = 10;
    }
}
std::cout << outer::inner::value << std::endl; // 输出:10

1.5 控制流

1.5.1 条件语句

C++ 的条件语句包括 ifelse ifelse

cpp
if (score > 90) {
    std::cout << "Excellent" << std::endl;
} else if (score > 75) {
    std::cout << "Good" << std::endl;
} else {
    std::cout << "Needs Improvement" << std::endl;
}

NOTE

避免过度嵌套的条件语句 为了使代码更清晰易懂,尽量减少过度嵌套的条件语句。例如,如果可以提前返回或退出循环,尽量选择这种方式来避免不必要的嵌套。

1.5.2 switch 语句

switch 语句用于多分支条件选择,在需要根据某个表达式的不同值执行不同操作时非常有用。

cpp
switch (grade) {
case 'A':
    std::cout << "Excellent" << std::endl;
    break;
case 'B':
    std::cout << "Good" << std::endl;
    break;
case 'C':
    std::cout << "Pass" << std::endl;
    break;
default:
    std::cout << "Fail" << std::endl;
    break;
}

NOTE

别忘了使用 breakswitch 语句中,别忘了在每个 case 后使用 break 语句。如果省略 break,控制流会继续执行后续的 case 代码,直到遇到 breakswitch 语句结束。这种行为叫做贯穿,在某些情况下可能有用,但大多数情况下是不希望发生的。

1.5.3 循环结构

C++ 中有三种主要的循环结构:whiledo-whilefor 循环。

while 循环

cpp
int i = 0;
while (i < 5) {
    std::cout << i << std::endl;
    ++i;
}

do-while 循环

cpp
int i = 0;
do {
    std::cout << i << std::endl;
    ++i;
} while (i < 5);

for 循环

cpp
for (int i = 0; i < 5; ++i) {
    std::cout << i << std::endl;
}

NOTE

选择合适的循环结构 while 循环在循环前先判断条件,而 do-while 循环则是先执行一次再判断条件。因此,当你需要确保循环体至少执行一次时,选择 do-while 循环。如果知道循环次数,for 循环通常更适合。(例外:一些 OI 题中会有多组测试数据,为了避免占用常用的循环变量 i,最大层循环通常使用 while(t--) 的形式完成)

1.5.4 break 和 continue

  • break 用于提前终止循环。
  • continue 用于跳过当前循环的剩余部分,直接进入下一次循环迭代。
cpp
for (int i = 0; i < 10; ++i) {
    if (i == 5)
        break; // 终止循环
    std::cout << i << std::endl;
}

for (int i = 0; i < 10; ++i) {
    if (i % 2 == 0)
        continue; // 跳过偶数
    std::cout << i << std::endl;
}

NOTE

避免滥用 breakcontinue :虽然 breakcontinue 是非常实用的控制流工具,但通常只在少数部分为了简化代码出现,过度使用它们会让代码变得难以理解(并且这种需求通常可以选择其他控制流语句完成特别是在嵌套循环或条件语句中。应谨慎使用这些语句,确保代码的可读性。

1.6 类简介

类是 C++ 支持面向对象编程的核心概念。通过类,程序员可以将数据与操作这些数据的方法打包在一起,从而实现更高层次的抽象和代码复用,很多标准库容器就是系统自带的类,C++ 还允许开发者创建和这些内置类型一样方便易用的类类型

什么是类

  • 是 C++ 中的一种用户自定义类型,它可以封装数据成员(通常是变量)和成员函数(也称为方法
  • 对象是类的实例,通过类创建对象 **,就像通过数据类型创建变量一样。

类允许程序员将数据和相关操作结合在一起,实现信息隐藏和模块化设计。

cpp
class Sales_item {
  public:
    double avg_price() const;
    // 成员函数声明
  private:
    std::string isbn;        // 数据成员:书号
    unsigned units_sold = 0; // 数据成员:销售数量
    double revenue = 0.0;    // 数据成员:收入
};
  • public:对外公开的成员,类的用户可以直接访问。
  • private:私有成员,外部用户无法直接访问,只能通过类的成员函数操作。

定义成员函数

在类的声明中,成员函数只是声明,可以在类外实现。

cpp
double Sales_item::avg_price() const {
    return (units_sold == 0) ? 0 : revenue / units_sold;
}
  • Sales_item:: 指明 avg_priceSales_item 类的成员函数。
  • const 表明函数不会修改成员变量的值。

NOTE

封装是面向对象编程的重要特性,封装允许类的设计者隐藏内部实现细节,用户只能通过类的接口与对象交互。这种方式有助于减少复杂性和避免意外错误。

使用类的对象

创建类的对象与创建内置类型的变量类似,使用类定义的对象可以调用其公有成员函数。