第2章 变量和基本类型
本文最后更新于:2023年8月25日 晚上
第2章 变量和基本类型
1. 基本内置类型
C++ 基本的数据类型有 算术类型和空类型,算术类型就是基本的整型和浮点型的数据类型。
不同类型之间的转换需要注意,有的转换可能是我们不想发生的。
字面值常量
- 数值型,编译器会根据数字形式对应一种基本的数据类型。
- 字符和字符串字面常量
- 布尔字面值和指针字面值
与其他整型不同, 字符型被分为了三种:char、signed char 和 unsigned char,但表现形式只有带符号和无符号两种。 char实际上会表现为signed char和unsigned char中的一种,由编译器决定。
2. 变量
变量提供一个具名的、可供程序操作的存储空间。
2.1 变量定义
C++变量的定义要指定变量的类型。 1
2
3
4
5
6//变量定义并初始化
int a = 2;
//变量定义
int b;
//变量赋值
b = 1;
在C++中变量的初始化和赋值是有区别的,
int a = 2;
的=
运算符表示的是初始化,而在
b=1;
中的=
是赋值。
C++11 初始化
1 |
|
使用 {}
来初始化变量,称为列表初始化,如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错
。
1 |
|
总结:C++变量初始化的语法形式有三种:
=
,()
,{}
默认初始化 ,定义变量时没有初始化变量的值,则变量会被默认初始化。默认初始化的值取决于变量定义的类型。定义在函数体内的局部变量和类中的成员属性是不会被初始化的。所以不用试图使用任何方式去访问这些变量。
2.2 声明和定义
声明,使程序知道变量(对象)的存在
定义,负责创建与名字关联的实体
1 |
|
变量能且只能被定义一次,但是可以被多次声明
2.3-4 标识符、作用域
标识符
变量命名按照规范,不要使用保留关键字。
- 普通的局部变量和函数参数名使用小驼峰(第一个单词首字母小写,其他单词首字母大写),
例:
userName
- 全局变量前加
g_
, 后面的按小驼峰规则 ,g_userName
- 静态变量前加
s_
, 后面按小驼峰规则,s_userName
- 类名使用大驼峰,所有单词的首字母大写 ,
UserManage
- 类属性(成员变量)前面加
m_
,后面按小驼峰规则 ,m_userName
- 常量全部使用大写,多个单词用
_
分割,MAX_NUMBER
作用域
局部变量不宜和全局的变量重名,嵌套的块,内部的不要和外部的重名。
3. 复合类型
一条声明语句由一个 基本数据类型 和紧随其后的一个 声明符 列表组成。
3.1 引用
引用 就是为变量(对象)起一个别名
1 |
|
注意:
- 引用只能绑定在对象上,而不能与字面值或表达式计算结果绑定
- 引用必须初始化,且不能改变
&
符号可以紧靠基本类型(int), 也可以紧靠变量名- 因为引用本身不是一个对象,所以不能定义引用的引用
以上说的引用都是左值引用,C++11还有右值引用
3.2 指针
指针 就是一个整数,没有实际的数值大小,只是一个编号,这个编号指向的是内存中的某个地址。
指针 vs 引用:
- 指针本身是一个对象没允许对指针赋值和拷贝
- 在指针的生命周期内它可以先后指向几个不同的对象
- 指针无需在定义时赋值[1]
指针的定义
1 |
|
指针无论定义成什么基本类型,其值都是一个固定位数的整数,指针类型数据的大小取决于系统的位数
32bit的系统指针是4byte = 32 bit, 64 bit系统指针式 8 byte = 64bit
指定类型的指针
1 |
|
定义指定类型的指针只是为了提供操作数据时需要操作的字节数。
例如,
int
型的指针,在使用指针改变指向的数据时,改变的是以该指针变量为首地址的4个字节内存,同样对
int
型指针的加或减的操作也是以4个字节为基本单位
*
(解引用符) 和 &
(取地址符)
1 |
|
赋值和指针
1 |
|
指针使用建议:
- 指针定义是可以不初始化,但建议定义时初始化,如果没有想好指向哪个变量,可以初始化为空指针
- 操作指针时,须确定操作的不是空指针和野指针(无效指针)
3.3 理解复合类型的声明
1 |
|
Tip: 面对一条比较复杂的指针或引用的声明语句时,从右向左读有助于弄清楚它的真实含义。
离变量名最近的符号(此例中是&r 的符号&)对变量的类型有最直接的影响,因此 r 是 一个引用。声明符的其余部分用以确定 r 引用的类型是什么,此例中的符号*说明 r 引用的是一个指针。最后,声明的基本数据类型部分指出 r 引用的是一个 int 指针 。
4. const 限定符
const 用于定义一个不能改变的变量, 所以定义时就必须初始化
1 |
|
const
定义的变量只对本文件可见,要使其他文件也可见需使用extern
4.1 const的引用
对常量的引用不能被用作修改它所绑定的对象
允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式(此时常量引用实际上绑定了一个临时量对象)
1 |
|
组合关系
int i |
cont int i |
|
---|---|---|
int &r |
✔ | ❌ |
cont int &r |
✔ | ✔ |
4.2 指针和const
指向常量的指针和对常量的引用类似:
int i |
cont int i |
|
---|---|---|
int *p |
✔ | ❌ |
cont int *p |
✔ | ✔ |
Tip: 所谓指向常量的指针或引用,不过是指针或引用“自以为是”罢了,它们觉得自己指向了常量,所以自觉地不去改变所指对象的值。
常量指针
1 |
|
从右向左读
C++ Primer 5th :
常量指针: 该变量是一个指针,指针本身是一个常量,即它的指向初始化后不可以改变
4. 3 顶层const
顶层const : 表示该变量(对象)本身是常量,不可以改变
底层const: 表示指向的变量(对象)是一个常量
1 |
|
引用类型的变量自带顶层const 即引用一旦赋值(指向某个变量)就不可以再变化(指向另一个变量)
4.4 constexpr和常量表达式
指值不会改变并且在编译过程就能得到计算结果的表达式。
constexpr和指针
一个constexpr 指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象
1 |
|
p2 和p3是等价的,
constexpr
修饰指针变量是被定义为顶层const
5. 处理类型
为了复杂程序更加易读易写,通常会给类型取别名,或是利用C++提供的特性自动推导复杂类型。
5.1 类型别名
typedef
传统的方法是使用 typedef
关键字定义类型别名
1 |
|
using
C++11
提供了一种新的方式,使用 using
1 |
|
这里的
using
要和using namespace std;
中的using
区分开。后者是表示引入命名空间,类似于java和python的导包操作
指针、常量和类型别名
1 |
|
第二行的定义不能理解成 const char *cstr = 0;
const pstring
中const
是对pstring
的修饰,而pstring
是一个char*
类型,因此const pstring
是指向 char的 常量指针 ,而并不是指向常量字符的指针
5.2 auto 类型说明符
auto
类型说明符可以让编译器分析表达式所属的类型。
1 |
|
复合类型、常量和auto
当使用引用类型推导类型时,
auto
推导的类型是引用指向变量的实际类型1
2int i = 0; &r = i;
auto a = r; // r是int型的引用,因此a是int型auto
会忽略掉顶层const, 同时底层const则会保留下来1
2
3
4
5const int ci = i, &cr = ci;
auto b = ci; //int b = ci;
auto c = cr; //int c = cr; cr是ci的别名,ci本身是一个顶层const
auto d = &i; //int *d = &i;
auto e = &ci; //const int *e = &ci; 对常量对象取地址是一种底层const如果希望推断出的auto类型是一个顶层const,需要明确指出:
1
const auto f = ci; // const int f = ci;
指定引用类型
1
2
3auto &g = ci; //const int &g = ci;
auto &h = 42; //错误,int &h = 42;
const auto &j = 42; //const int &j = 42;
auto 使用建议:
使用auto声明变量一定要做到心里有数,你知道编译器会推断出的什么样的类型
通常使用auto是对于一些类型名比较复杂的变量,使用auto写起来更方便
5.3 decltype 类型指示符
C++11 decltype
可以不执行表达式,编译器自动推断出表达式的返回值类型
1 |
|
通过 f()
推断出返回类型,但是并不会执行
f()
decltype 和const
decltype
处理顶层 const和引用的方式和auto有点不同,如果
decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)
1 |
|
decltype 和引用
1 |
|
r
是引用decltype(r)
是引用,但是r + 0
是一个int型数据解引用指针得到的是指针所指的对象,,因此
decltype(*p)
是int&
变量加上 ()
得到的是引用类型
1 |
|
6. 自定义数据结构
这里的自定义数据结构就是指类类型的数据,在C++中定义类的关键字有class
和 struct
1 |
|
class
和struct
在功能上是完全一样的,两者唯一的不同是默认的权限不同
class
默认的权限是私有的(private), 而struct
是公有的(public)
注意:c语言中的结构体是不能有方法(函数)
关于类更具体的介绍在后面的章节~~
- 但建议定义时初始化,如果没有想好指向哪个变量,可以初始化为空指针。 ↩︎