2.1 基本内置类型
2.1.1 基本数据类型:算术类型和空类型(void)
算术类型:整型和浮点型
类型 | 含义 | 最小尺寸 |
bool | bool类型 | 未定义 |
char | 字符 | 8位 |
wchat_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 32位 |
char32_t | Unicode字符 | 16位 |
short | 短整型 | 16位 |
int | 整型 | 32位 |
long | 长整型 | 64位 |
long long | 长整型 | 6位有效数字 |
float | 单精度浮点数 | 10位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
int main()
{
cout<< sizeof(bool)<<" "<<sizeof(char) << " " << sizeof(wchar_t) << " "
<< sizeof(char16_t) << " " << sizeof(char32_t) << endl;
cout << sizeof(short) << " " << sizeof(int) << " " <<
sizeof(long) << " " << sizeof(long long) << endl;
cout << sizeof(float) << " " << sizeof(double) << " "
<< sizeof(long double) << endl;
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/4c2f6156975d015b63362b61c2c71054.png)
的运行结果
除去布尔型和拓展的字符型之外,其他整型可以分为带符号类型和无符号类型:在类型前添加unsigned就可以得到无符号类型。例如 unsigned int( 可以缩写为unsigned )、unsigned long。
如何选择类型:
- 当数值不可能为负时,选用无符号类型。
- 使用int执行整数运算,如果大于int,选用long long。
- 浮点运算选择double。
2.1.2 类型转换
转换:
- 非bool 与 bool :初始值为0,则bool类型为false;初始值不为0,则bool类型为true。
- 浮点数转整型:仅保留浮点数的整数部分。
- 整型转浮点数:小数部分记为0.
- 给无符号数一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。
- 给带符号数一个超出它范围的数,结果是未定义的。
- 当有符号数和无符号数进行运算时,运算结果转换成无符号数。
2.1.3 字面值常量
- 整型字面值: 十进制 ( 20 )、 八进制( 024 )、 十六进制( 0x14 )
- 浮点型字面值:3.14159 、 3.14E0 、 0. 、 0e0 、 .001
- 字符和字符串字面值:‘a' 、 “Hello World”、
- 转义序列: \n, \t, \a, \v, \b, \", \\, \?, \', \r, \f \114 (后面为八进制,表示字符M) \x4d(后面为十六进制,表示字符M)
- 指定字面值的类型:字符和字符串字面值的前缀: L'a' (宽字符型), u8"hi!" (utf-8字符串字面值); 数值字面值的后缀 :42ULL (unsigned long long) , 42L(long) , 1e-3f( float ) 3.14159L ( long double );
- bool字面值:true,false;
- 指针字面值:nullptr ;
2.2 变量
变量提供一个具名的、可供程序操作的存储空间。C++中每个变量都有数据类型,数据类型决定变量所占内存空间的大小和布局方式、该空间能存储的值的范围以及变量能够参与的运算。
2.2.1 变量定义
形式: 类型说明符 变量1,变量2,... ,变量n ;
int sum =0,value,units_sold=0;
Sales_item item; //Sales_item 为自定义的类型。
std::string book("0-201-78345-x") ; //库类型
初始化: 初始化不是赋值,初始化的含义是创建变量时赋予其中一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来代替。
C++11新标准-列表初始化:特点:当使用列表初始化且初始化值存在丢失风险时,编译器将报错:
int units_sold =0;//以前的初始化
int units_sold(0);
int units_sold = {0};//列表初始化
int units_sold{0};
double d = 3.1415926;
int i{ d };//编译报错
//错误信息如下:
//Error C2397 conversion from 'double' to 'int' requires a narrowing conversion
默认初始化:定义于任何函数体之外的内置类型的变量被初始化为0. 定义在函数体内部的内置类型将不被初始化。每个类各自决定其初始化对象的方式。
2.2.2 变量声明和定义的关系
为了允许把程序拆分为多个逻辑部分来编写,C++语言支持分离式编译机制。因此,C++语言将声明和定义区分开来。声明使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。定义负责创建与名字关联的实体。
声明:在变量名前添加关键字extern,而且不要显式地初始化变量。例如 extern int i;
在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。
2.2.3 标识符
C++的标识符由字母、数字和下划线组成,其中必须以字母或下划线开头。标识符的长度没有限制,但是大小写敏感。
变量命名规范:
- 体现实际含义。
- 变量名小写。
- 自定义类名开头大写。
- 多个单词时,单词间应该有明显的区分。
2.2.4 名字的作用域
- 作用域:一般指成对的花括号中间为一个作用域。
- 全局作用域:定义于所有花括号之外的名字具有全局作用域。一旦声明以后,全局作用域内的名字在整个程序范围内都可使用。
- 当出现嵌套的作用域时,被包含的作用域称为内层作用域,包含着别的作用域的的作用域称为外层作用域。在一个嵌套中,内层作用域可以访问外层作用域的名字,但是外层作用域无法访问内层作用域的名字。
2.3 复合类型
2.3.1 引用-左值引用
- 引用:为对象起了另一个名字。
- 引用必须初始化。
- 引用本身不是一个对象不能定义引用的引用。
- 一般情况下,引用类型和其绑定对象的类型严格匹配。而且,引用不能绑定在字面值和临时变量上。
int ival =1024;
int &refVal = ival; //refVal是一个int的引用类型
int &refVal1; //错:引用必须初始化
int &refVal2 = 10; //错:普通的引用不能用字面值初始化
double dval = 3.14;
int &refVal3 = dval;//错:引用的类型需要严格匹配
2.3.2 指针
- 指针与引用相比:
- 指针本身是一个对象,允许指针赋值和拷贝。可以先后指向不同的对象。
- 指针无需在定义时赋初值。
- 指针值:指针的值一般有4种状态,
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置。
- 空指针
- 无效指针,上述三种情况之外的其他值。
- 空指针:不指向任何对象,在试图使用一个指针前代码首先要检查它是否为空。
- 建议:初始化所有指针。访问未经初始化的指针所引发的后果是无法预计的。因此在可能的情况下,定义了对象之后再定义指向它的指针;否则,把它初始化为nullptr。
- 指针的操作:赋值、同类型的比较、
- void *指针:一种特殊的指针类型,可用于存放任意对象的地址。
double dval = 3.14159 ;
double *pd = &dval; //pd中保存dval变量的地址
double *pd2 = pd; //pd2中保存dval变量的地址
int *pi = pd; //错误:指针pi的类型和pd的类型不匹配
int *p1 = nullptr; //空指针
if( pd != nullptr ) //解引用只适用于有效指针,不能对空指针解引用
std::cout<< *pd <<std::endl; //利用*对指针解引用得到所指对象的值
2.3.3 理解复合类型的声明
int i =42;
int *p1=&i,p2=0; //p1是int指针,p2是int;
int ** pi = p1; //ppi是int指针的指针;
int * &r = p1; //r为指针p1的引用;
*r = 0; //将i的值改为0;
2.4 const限定符
- const 对象一旦创建后其值就不能再改变,所以const对象必须初始化。
- 默认状态下,const对象仅在文件内有效。如果需要共享const对象,则需要在定义前添加extern。并在其他文件中声明。
- const的引用(常量引用):把引用绑定到const对象上。在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能够转换成引用的类型即可。const引用可能引用一个非const的对象。
- 实际上const引用会先把字面值或者需要类型转换的对象用一个临时变量存起来,然后const引用会绑定这个临时变量。
- 一般来说,C++ 中的临时变量在表达式结束之后 (full expression) 就被会销毁,比如函数的返回值或者类型转换时的中间变量。但也有例外的时候,如果这个临时变量被用来初始化一个引用的话,那这个临时变量的生命周期就会被延长,直到引用被销毁,从而不会因此产生悬空(dangling)的引用。
int i=42;
const int ci = i; //正确:i的值被拷贝给了ci
int j = ci; //正确,ci的值被拷贝给了j
const int &r1 = ci; //正确,对象和引用都是常量
int &r2 = ci; //错误,一个非常量引用不能绑定一个常量对象
const &r3 = 42; //right,
const &r4 = r3*2; //right,
int &r5 = r3*2; //wrong, initial value of reference to non-const must to be lvalue
- 指向常量的指针:不能用于改变其所指对象的值。
- const指针:指针是常量,不允许改变指针的值。必须初始化
//a pointer to const
const double pi = 3.14;
double *ptr = π //wrong, ptr must be a pointer to const;
const double * cptr = π //right.
*cptr = 42; //wrong,
double dval = 3.14;
cptr = &dval;
//const pointer
int errNumb = 0;
int * const curErr = &errNumb;
const double pi = 3.14159;
const double * const pip = π
- 顶层const表示指针本身是个常量,底层const表示指针所指的对象是一个常量。
- 更一般的,顶层const可以表示任意的对象是常量。底层const则与指针和引用等复合类型的基本类型有关。
int i=0;
int * const p1 = &i; //top-level const
const int ci =42;
const int *p2 = &ci; //low-level const
const int * const p3 = p2;
int *p = p3; //wrong
const int * pp = p3; //right
int & r =ci; //wrong
int & r2 = ci; //right
- 常量表达式是指不会改变并且在编译过程就能得到计算结果的表达式。
- 允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。如果认定一个变量时一个常量表达式,那就把它声明成constexpr类型。
2.5 处理类型
2.5.1 类型别名
- typedef / using
//two method : typedef / using
typedef double wages; //wages:double
typedef wages base,*p; //base:double ; p :double * ;
using SI = Sales_item; //SI : Sales_item
//const , pointer and type alias
typedef char * pstring;
const pstring cstr = 0; // a const pointer to char;
const pstring * ps = &cstr ; //a pointer to a const pointer to char;
2.5.2 auto类型说明符
- auto让编译器通过初始值来推算变量的类型。auto定义的变量必须要有初始值。
- 可以使用auto声明多个变量,但是所有变量的初始基本数据类型必须一样。
- 当引用作为初始值的时候,忽略引用类型,只保留引用对象的类型。
- auto忽略顶层const,保留底层const
auto i=0,*p = &i; //right , i :int, p: pointer to int
auto sz =0,pi=3.14; //wrong , sz:int , pi:double
int i=0,&r = i;
auto a = r; // a:int
const int ci = i,&cr = ci;
auto b = ci; // b:int
auto c = cr; // c:int
auto d = &ci; // d:a pointer to const int
const auto & e = ci; // e:const reference to int
2.5.3 decltype
- decltype:分析表达式并得到它的类型,却不实际计算表达式的值。
- decltype的表达式一个变量时,则返回该变量的类型,包括顶层const和引用。
- 注意最后一行的情况。
const int ci=0,&cj=ci;
decltype(ci) x = 0; // x:const int
decltype(cj) y = x; // y:const int &
decltype(cj) z; //wrong, z:const int &, must initial
int i=42,*p =&i,&r = i;
decltype(r+0) b; //b:int
decltype(*p) c; //wrong, c:int & ,must initial
decltype((i)) d; //wrong, d:int & ,must initial