必会知识 | C++变量

@[toc]

1. 类型

C++中的变量类型非常丰富,主要分为以下几大类:

  • 基本数据类型

    • 整数类型:intshortlonglong long(及其无符号版本,如unsigned intunsigned long等)。这些类型用于存储整数值,大小根据编译器和平台而异,但通常有固定的最小值。
    • 浮点类型:floatdoublelong double。这些类型用于存储带有小数部分的数值,大小和精度依次递增。
    • 字符类型:charwchar_tchar16_tchar32_t。这些类型用于存储单个字符,char通常为1字节,wchar_tchar16_tchar32_t分别用于存储宽字符,大小可能因平台而异。
    • 布尔类型:bool。这是一个逻辑类型,只能存储truefalse两个值。
  • 复合数据类型

    • 数组(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 intunsigned char等。

4. 类型转换

4.1 隐式转换与显式转换

  • 隐式转换:编译器自动进行的类型转换,通常发生在不同类型之间的赋值、函数调用参数传递或算术运算中。
  • 显式转换(强制类型转换):程序员通过类型转换运算符(如(type)expressionstatic_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++中,可以通过typedefusing关键字来定义类型别名。类型别名使得代码更加清晰易懂,尤其是在处理复杂类型或模板时。

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用于根据函数体内表达式的类型来推导函数的返回类型,这在模板编程中尤其有用。

类型别名、autodecltype是C++中用于类型推导和类型别名定义的重要工具,它们使得代码更加简洁、灵活和易于维护。

C/C++面试必考必会 文章被收录于专栏

【C/C++面试必考必会】专栏,直击面试核心,精选C/C++及相关技术栈中面试官最爱的必考点!从基础语法到高级特性,从内存管理到多线程编程,再到算法与数据结构深度剖析,一网打尽。助你快速构建知识体系,轻松应对技术挑战。希望专栏能让你在面试中脱颖而出,成为技术岗的抢手人才。

全部评论

相关推荐

点赞 评论 收藏
分享
点赞 2 评论
分享
牛客网
牛客企业服务