必会知识 | C++变量
@[toc]
1. 类型
C++中的变量类型非常丰富,主要分为以下几大类:
-
基本数据类型:
- 整数类型:
int
、short
、long
、long long
(及其无符号版本,如unsigned int
、unsigned long
等)。这些类型用于存储整数值,大小根据编译器和平台而异,但通常有固定的最小值。 - 浮点类型:
float
、double
、long double
。这些类型用于存储带有小数部分的数值,大小和精度依次递增。 - 字符类型:
char
、wchar_t
、char16_t
、char32_t
。这些类型用于存储单个字符,char
通常为1字节,wchar_t
、char16_t
、char32_t
分别用于存储宽字符,大小可能因平台而异。 - 布尔类型:
bool
。这是一个逻辑类型,只能存储true
或false
两个值。
- 整数类型:
-
复合数据类型:
- 数组(Array):存储相同类型元素的连续内存区域。
- 结构体(Struct):将不同类型的数据聚集到一个对象中。
- 联合体(Union):使用相同的内存位置存储不同类型的数据,但一次只能使用其中一个成员。
- 类(Class):封装数据和函数的用户定义类型。
- 枚举(Enum):定义具有离散取值集合的新类型。
-
指针和引用:
- 指针(Pointer):存储内存地址的变量,用于间接访问和修改数据。
- 引用(Reference):为变量起别名,必须在声明时初始化,且一旦被绑定到一个变量上,就不能再绑定到另一个变量上。
2. 大小
变量的大小取决于其类型,且可能因编译器和平台而异。在大多数现代编译器和平台上,常见类型的大小如下:
char
:通常1字节。short
:通常2字节。int
:至少与short
一样大,通常是4字节。long
:至少与int
一样大,可能是4字节或8字节。long long
:至少与long
一样大,通常是8字节。float
:通常是4字节。double
:通常是8字节。long double
:大小可能因平台而异,但至少与double
一样大。bool
:虽然C++标准未规定其大小,但通常是1字节。
3. signed 与 unsigned
- signed:表示有符号类型,可以存储正数、负数和零。默认的整型(如
int
)都是有符号的。 - unsigned:表示无符号类型,只能存储非负数(包括零)。无符号类型以
unsigned
关键字开头,如unsigned int
、unsigned char
等。
4. 类型转换
4.1 隐式转换与显式转换
- 隐式转换:编译器自动进行的类型转换,通常发生在不同类型之间的赋值、函数调用参数传递或算术运算中。
- 显式转换(强制类型转换):程序员通过类型转换运算符(如
(type)expression
、static_cast<type>(expression)
、dynamic_cast<type>(expression)
、const_cast<type>(expression)
、reinterpret_cast<type>(expression)
)明确指示的类型转换。
4.2 算术转换
在进行算术运算时,编译器会根据一套规则(称为算术转换)自动提升操作数的类型。这通常涉及将较小的整数类型提升为较大的整数类型,或者将有符号类型转换为无符号类型(如果无符号类型足够大以包含转换后的值)。
5. 初始化与赋值
- 初始化:在创建变量时赋予其初始值。初始化可以发生在声明时(如
int a = 5;
),也可以在构造函数中(对于类类型的对象)。 - 赋值:在变量创建后给其赋予新值。赋值使用赋值运算符
=
,如a = 10;
。赋值与初始化不同,初始化是在变量生命周期开始时赋予初始值,而赋值是在变量生命周期内改变其值。
6. 声明与定义
- 声明:向编译器介绍一个名字,但不分配内存空间。它告诉编译器名字的类型和可能的属性,但直到定义时才会分配内存。变量可以在多个地方声明,但只能在一个文件中定义一次(除非使用了
extern
关键字)。 - 定义:为变量分配内存空间,并可能初始化它。定义包含了变量的所有细节,包括其类型、名称和(可选的)初始值。一个变量只能被定义一次,但可以被多次声明。
7. 作用域
作用域定义了程序中名字(如变量名、函数名等)的可见性和生命周期。C++中有几种作用域:
- 全局作用域:在所有函数之外声明的名字,它们在程序的整个执行期间都是可见的。
- 局部作用域:在函数内部、代码块(如
{}
内的代码)中声明的名字,它们仅在该代码块内可见。 - 类作用域:在类内部声明的名字,它们对类及其成员函数是可见的。
- 命名空间作用域:在命名空间内声明的名字,它们通过命名空间来访问。
8. 复合类型
复合类型是由基本类型(如int、float等)组合而成的更复杂的数据类型。
8.1 引用
- 引用是某个已存在对象的别名。在声明引用时,必须初始化它,且一旦与某个对象绑定后,就不能再改变为引用另一个对象。
- 语法:
类型& 引用名 = 对象名;
- 引用常用于函数参数和返回值,以避免不必要的拷贝,提高效率。
8.2 指针
- 指针是存储变量地址的变量。通过指针,我们可以直接访问和操作内存中的数据。
- 语法:
类型* 指针名;
- 指针可以指向变量的地址、数组的元素、函数的地址等。
- 解引用指针(
*指针名
)可以得到指针所指向的值。
8.3 复合类型的声明
复合类型的声明可能涉及引用和指针的复杂组合,例如指向指针的指针、指向引用的指针(实际上不可能,因为引用不是对象,没有地址)等。
9. const
- const关键字用于修饰变量,表示该变量的值在初始化后不能被修改。
- 修饰指针时,可以指定指针本身不能被修改(指向常量的指针),或者指针指向的值不能被修改(常量指针),或者两者都不可修改(指向常量的常量指针)。
- 修饰函数参数时,可以保护传入参数不被函数内部修改。
- 修饰成员函数时,表示该函数不会修改任何成员变量的值(const成员函数)。
10. constexpr 与常量表达式
- constexpr是C++11引入的,用于声明编译时常量表达式。被
constexpr
修饰的变量或函数必须在编译时就能确定其值。 - 常量表达式是指值在编译时就已知的表达式。使用
constexpr
声明的变量或函数的结果必须是常量表达式。 constexpr
可以用于变量声明、函数声明(返回类型为字面量类型)以及类成员函数中,但有一定的限制条件。constexpr
提高了程序的可读性和可维护性,同时可能允许编译器进行更多的优化。
11. 类型别名
类型别名是给一个类型起一个新的名字。在C++中,可以通过typedef
或using
关键字来定义类型别名。类型别名使得代码更加清晰易懂,尤其是在处理复杂类型或模板时。
typedef
示例:
typedef int Integer; // Integer是int的别名
Integer i = 10; // 等同于int i = 10;
using
示例(C++11及以后):
using Integer = int; // Integer是int的别名
Integer j = 20; // 等同于int j = 20;
12. auto
auto
关键字用于自动类型推导。在C++11及以后的版本中,auto
使得编译器能够自动推断变量的类型,这在编写模板代码或处理复杂表达式时特别有用。使用auto
可以使代码更加简洁,但需要注意不要过度使用,以免降低代码的可读性。
示例:
auto x = 10; // x的类型是int
auto y = 20.5; // y的类型是double
auto z = 'a'; // z的类型是char
// 复杂类型推导
std::vector<int> v = {1, 2, 3, 4, 5};
auto it = v.begin(); // it的类型是std::vector<int>::iterator
13. decltype
decltype
关键字用于查询表达式的类型,但不实际计算表达式的值。它主要用于模板编程和泛型编程中,当需要知道某个表达式的类型但又不想执行该表达式时。decltype
使得程序员能够编写更加灵活和强大的代码。
示例:
int x = 0, &r = x;
decltype(r + 0) b; // b的类型是int
decltype((r)) a = x; // 注意双括号,a的类型是int&
// 函数返回类型推导
auto add(int x, int y) -> decltype(x + y) {
return x + y;
}
// C++14及以后,可以使用auto直接推导函数返回类型
auto add(int x, int y) {
return x + y;
}
// decltype用于模板编程
template<typename T, typename U>
auto add(T x, U y) -> decltype(x + y) {
return x + y;
}
在上面的decltype
示例中,第一个decltype
示例展示了如何根据表达式的类型来推导变量b
的类型。第二个示例展示了如何使用decltype
和引用折叠规则来推导变量a
的类型为int&
。在函数返回类型推导的示例中,decltype
用于根据函数体内表达式的类型来推导函数的返回类型,这在模板编程中尤其有用。
类型别名、
auto
和decltype
是C++中用于类型推导和类型别名定义的重要工具,它们使得代码更加简洁、灵活和易于维护。
【C/C++面试必考必会】专栏,直击面试核心,精选C/C++及相关技术栈中面试官最爱的必考点!从基础语法到高级特性,从内存管理到多线程编程,再到算法与数据结构深度剖析,一网打尽。助你快速构建知识体系,轻松应对技术挑战。希望专栏能让你在面试中脱颖而出,成为技术岗的抢手人才。