在课程 4.1 — 基本数据类型简介 中,我们介绍了基本数据类型,它们是 C++ 作为核心语言提供的一种基本数据类型。
到目前为止,我们已经在程序中大量使用了这些基本类型,尤其是 int
数据类型。虽然这些基本类型对于直接的用途非常有用,但当我们开始做更复杂的事情时,它们无法满足我们的全部需求。
例如,假设您正在编写一个数学程序来乘以两个分数。您将如何在程序中表示分数?您可以使用一对整数(一个用于分子,一个用于分母),如下所示
#include <iostream>
int main()
{
// Our first fraction
int num1 {};
int den1 {};
// Our second fraction
int num2 {};
int den2 {};
// Used to eat (remove) the slash between the numerator and denominator
char ignore {};
std::cout << "Enter a fraction: ";
std::cin >> num1 >> ignore >> den1;
std::cout << "Enter a fraction: ";
std::cin >> num2 >> ignore >> den2;
std::cout << "The two fractions multiplied: "
<< num1 * num2 << '/' << den1 * den2 << '\n';
return 0;
}
以及此程序的运行
Enter a fraction: 1/2 Enter a fraction: 3/4 The two fractions multiplied: 3/8
虽然这个程序有效,但它给我们带来了一些需要改进的挑战。首先,每对整数之间的关联性很弱——除了注释和它们在代码中使用的方式的上下文之外,很少有迹象表明每对分子和分母是相关的。其次,遵循 DRY(不要重复自己)原则,我们应该创建一个函数来处理用户输入分数(以及一些错误处理)。但是,函数只能返回一个值,那么我们如何将分子和分母返回给调用者呢?
现在想象另一种情况,您正在编写一个需要保存员工 ID 列表的程序。您可能会怎么做?您可能会尝试以下方法
int main()
{
int id1 { 42 };
int id2 { 57 };
int id3 { 162 };
// and so on
}
但是如果你有 100 名员工怎么办?首先,你需要输入 100 个变量名。如果你需要打印所有这些呢?或者将它们传递给一个函数?我们会打很多字。这根本无法扩展。
显然,基本类型只能帮助我们到此为止。
复合数据类型
幸运的是,C++ 支持第二组数据类型:复合数据类型(有时也称为组合数据类型)是根据其他现有数据类型定义的类型。复合数据类型具有额外的属性和行为,使其对于解决某些类型的问题非常有用。
关键见解
每种数据类型都是基本类型或复合类型。C++ 语言标准明确定义了每种类型所属的类别。
正如我们将在本章和未来的章节中展示的,我们可以使用复合数据类型优雅地解决我们上面提出的所有挑战。
C++ 支持以下复合类型
- 函数
- C 风格数组
- 指针类型
- 指向对象的指针
- 指向函数的指针
- 指向成员类型的指针
- 指向数据成员的指针
- 指向成员函数的指针
- 引用类型
- 左值引用
- 右值引用
- 枚举类型
- 无作用域枚举
- 有作用域的枚举
- 类类型
- 结构体
- 类
- 联合体
您已经经常使用一种复合类型:函数。例如,考虑这个函数
void doSomething(int x, double y)
{
}
此函数的类型为 void(int, double)
。请注意,此类型由基本类型组成,使其成为复合类型。当然,函数也有其自身的特殊行为(例如可调用)。
由于这里有很多材料要涵盖,我们将分多个章节进行。在本章中,我们将介绍一些更直接的复合类型,包括 l-value references
和 pointers
。下一章,我们将介绍 unscoped enumerations
、scoped enumerations
和我们的第一个类类型:structs
。然后,在之后的章节中,我们将介绍类并深入探讨一些更有用的 array
类型。这包括 std::string
(在课程 5.7 — std::string 简介 中介绍),它实际上是一个类类型!
命名法
类类型是结构体、类或联合体。我们将在未来的课程中大量使用这个术语。
准备好了吗?开始吧!