算术类型分为两类:整型 和 浮点型
C++:算术类型 |
||
类型 | 含义 | 最小尺寸 |
bool | 布尔类型 | 8bits |
char | 字符 | 8bits |
wchar_t | 宽字符 | 16bits |
char16_t | Unicode字符 | 16bits |
char32_t | Unicode字符 | 32bits |
short | 短整型 | 16bits |
int | 整型 | 16bits (在32位机器中是32bits) |
long | 长整型 | 32bits |
long long | 长整型 | 64bits (是在C++11中新定义的) |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
wchar_ t类型用于确保可以存放 机器最大扩展字符集 中的任意一个字符,类型char16_ t和char32_ t则为 Unicode字符集 服务。
如何选择类型:
类型所能表示的值的范围决定了转换的过程:
注:当一个算术表达式中 既有无符号数又有无符号数 时,有符号数就会转换成无符号数。
字面值常量:
注:初始化不是赋值!(初始化 = 创建变量 + 赋予初始值;赋值 = 擦除对象的当前值 + 用新值代替)
变量的 声明 vs 定义:
为了支持分离式编译,C++将声明和定义区分开。声明 使得名字为程序所知。定义 负责创建与名字关联的实体。
使用 extern 只是说明变量定义在其他地方。
如果只声明而不定义,则在变量名前添加 关键字extern (如extern int i);但如果包含了初始值,就变成了定义。(extern double pi = 3.14(),也就抵消了extern的作用)
变量只能被定义一次,但是可以多次声明。
C++是一种静态类型语言,其含义是在编译阶段检查类型。
引用:引用是对象的别名(引用本身不是对象)
指针:指针是指向任何其他类型对象的对象(指针本身就是对象,存放被指向对象的地址)
void*指针可以存放任意对象的地址,其他指针类型必须要与所指对象严格匹配。
空指针不指向任何对象。(被 字面值nulltptr 初始化的指针就是空指针)
两个指针相减的类型是ptrdiff_t。
建议:初始化所有指针。
int i = 42;
int &r = i; // &紧随类型名出现,因此是声明的一部分,r是一个引用
int p; // *紧随类型名出现,因此是声明的一部分,P是一个指针
P = &i; // &出现在表达式中,是一个取地址符
*p = i; // *出现在表达式中,是一个解引用符
int &r2 = *p; // &是声明的一部分,*是一个解引用符
注:在声明语句中,&和*用于组成复合类型;在表达式中,它们的角色又转变成运算符。
int i = 1;
int *p; // p是一个int型指针
int *&r = p; // r是一个对指针p的引用(离变量名最近的符号(&)对变量类型有最直接的影响,因此r是一个引用,声明符的剩余部分(*)用以确定r的类型是什么,所以最终可知r引用的是一个指针)
r = &i; // r引用了一个指针,因此给r赋值&i就是令p指向i
*r = 0; // 解引用r得到i,也就是p指向的对象,将i的值改为0
注:面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清楚它的真实含义。
动机:希望定义一些不能被改变值的变量。
引用的类型必须与其所引用对象的类型一致,但是有两个例外。
int i = 42;.
const int &r1 = i; // 允许将 const int&绑定到一个普通 int对象上
const int &r2 = 42; // 正确: r2是一个常量引用
const int &r3 = r1 * 2; // 正确: r1、r3都是常量引用
int &r4=r1 * 2; // 错误: r4是一个普通的非常量引用
const double& r5 = i; // 正确: int可以转换为double类型
注:常量引用并不是说引用本身是常量,因为引用都不是一个对象!所以常量引用指的是 引用的对象是个常量。
对const的引用可能引用一个并非const的对象
int i = 42;
int &r1 = i; // 引用r1绑定对象i
const int &r2 = i; // r2也绑定对象i,但是不允许通过r2修改i的值
r2 = 0; // 错误: r2是一个常量引用
r1 = 0; // 正确: r1并非常量,i的值修改为0(不允许通过r2修改i的值。尽管如此,i的值仍然允许通过其他途径修改)
注:必须认识到,常量引用仅对 引用可参与的操作 做出了限定,对于引用的对象本身是不是一个常量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值。
指针的类型必须与其所指对象的类型一致,但有个例外。
double i = 3.14;
const double* p = &i; // 正确
允许一个指向常量的指针指向一个非常量对象。
注:对除指针以外的其他变量声明语法来说 const type name 与 type const name 效果是相同的,即都表示声明一个 类型为type名为name 的常量。
顶层const:指针本身是个常量
底层const:指针指向的对象是个常量。
拷贝时严格要求相同的底层const资格
int i = 1;
const int* p = &i;
int* ptr1 = p; // 错误: "const int *"类型的值不能用于初始化"int *"类型的实体
const int* ptr2 = p; // 正确
const int n = 1;
int &r1 = n; // 错误: 将"int &"类型的引用绑定到"const int"类型的初始值设定项时,限定符被丢弃。
const int& r2 = n; // 正确
常量表达式:指值不会改变,且在编译过程中就能得到计算结果的表达式。
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量的表达式。
一个对象(或表达式)是不是常量表达式由它的 数据类型和初始值 共同决定。
const int max_files = 20; // max_files是常量表达式,
const int limit = max_files + 1; // limit是常量表达式
int staff_size = 27; // staff_size不是常量表达式(尽管staff_ size 的初始值是个字面值常量,但它的数据类型只是一个普通 int而非const int)
const int sz = get_size() ; // sz不是常量表达式(尽管sz本身是一个常量,但它的具体值直到运行时才能获取到)
声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
constexpr int mf = 20; // 20是常量表达式.
constexpr int limit = mf + 1; // mf + 1是常量表达式
constexpr int sz = size(); // 只有当size是一个constexpr函数时,才是一条正确的声明语句
constexpr把它所定义的对象置为顶层const。
int j = 0;
constexpr int i = 42; // i的类型是整型常量
// 注: i和j都必须定义在函数体之外。
constexpr const int *p = &i; // p是常量指针,指向整型常量i
constexpr int *p1 = &j; // pl是常量指针,指向整数j
注:后面俩句并不等价!
typedef char *pstring;
const patring cstr=0; // cstr是指向char的常量指针(const修饰pstring这个指针(char *),所以数据类型为 const char*,因此cstr是指向char常量指针)
const char *cstr=0; // cstr是指向一个常量对象的指针(const修饰char,所以数据类型为const char ,因此cstr是指向一个常量对象的指针)
auto让编译器通过 计算初始值 来推算变量的类型。
1. 用auto进行类型推导时(非引用)会忽略顶层const、保留底层const。
const int a = 1;
auto b = a; // b为 int 类型(忽略顶层const属性)
auto c = &a; // c是 const int* 类型(保留底层const属性)
2. 用auto推导引用类型时,实际推导的是引用所绑定的对象;而被绑定的对象即使包含顶层const,也会被忽略掉。
const int a = 1;
const int& y = a;
auto b = y; // b为 int 类型(实际推导的是引用所绑定的对象,并忽略顶层const属性)
3. 用auto类型推导,定义引用时,需要显示地定义引用,并且会保留顶层const。
const int a = 1;
auto& y = a; // y为const int类型的引用(保留了a的顶层const,而y本身变成了底层const)
4. 用auto定义多个变量时,*和&只属于声明符,而不是数据类型的一部分;因此类型必须一致。
auto &q = a, *p = &a; // 正确: q是对const int的引用,p是指向const int的指针
auto &c = b, *d = &a; // 错误: c的数据类型为int,d的数据类型为const int
decltype 分析表达式的类型 推断并返回操作数的数据类型。
1. 当使用 decltype(var) 的形式时,decltype会直接返回变量的类型(包括顶层const和引用)。
const int i = 0, &j = i; // i为const int,j为const int&
decltype(i) x = 0; // x的类型是const int
decltype(j) y = x; // y的类型是const int&
2. 当使用 decltype(expr) 的形式时,decltype会返回表达式结果对应的类型。
int i = 42, *p = &i, &r = i; // i是int类型变量,p是int类型指针,r是int类型引用(它们类型都为int,只是声明符不同而已)
decltype(r + 0) b; // b为int(算术表达式返回右值,即int)
decltype((i)) ri = i; // ri为int&(加了括号变量i变成了表达式,因此返回的是i的左值形式,即int&)
decltype(*p) c = i; // c是一个int类型引用
3. 当使用 decltype(函数指针) 的形式时,decltype会返回函数对应的类型。
int fun(int a,int b);
decltype(fun) *pf = fun; // pf为int(*)(int,int)类型
decltype加指针也会返回指针的类型。
decltype加数组,不负责把数组转换成对应的指针,所以其结果仍然是个数组。
总之decltype(var)完美保留了变量的类型。
#ifndef SALES_DATA_H
#define SALES_DATA_H
strct Sale_data{
...
}
#endif
#define指令:把一个名字设定为预处理变量
#ifdef指令:当且仅当预处理变量已定义时为真
#ifndef指令:当且仅当变量未定义时为真
#endif指令:一旦检查结果为真,则执行后续操作直至遇到#endif指令为止