一,基本内置类型
在C++中的基本类型,也包含了char,int,bool等常用了一些数据类型,在类型上也分为带符号类型和无符号类型。
1.带符号类型和无符号类型
- 带符号的类型前面用signed进行修饰,可以表示正数,负数或0
- 无符号的类型声明时用unsigned进行修饰,表示大于等于0的值类型int ,short,long和long long都是带符号类型,可通过添加unsigned修饰变成无符号类型。
- 对于字符类型,主要分为三种:char,signed char和unsigned char,其中char和signed char 是不一样的。
字符虽然有三种,但只有两种:带符号和无符号,类型char具体表现是什么类型取决于编译器。
注:
1)当明确知晓数值不可能为负时,选用无符号类型。
2)使用int执行整数运算。(short 太小,l如果数值超过了int范围时,使用long long)
3)算术表达式中不能使用char或bool
4)执行浮点数运算选用double(float通常精度不够且单双精度浮点运算的计算代价相差无几)
2.类型转换
根据需要或特定场景下,需要把一种类型转换为另外一个类型丢弃一些精度进行实际使用。
bool b = 42;
cout << "b --->:" << b << endl;
int i = b;
cout << "i --->:" << i << endl;
i = 3.14;
cout << "i new--->:" << i << endl;
double pi = i;
cout << "pi --->:" << pi << endl;
unsigned char c = -1;
cout << "c --->:" << c << endl;
signed char c2 = 256;
cout << "c2 --->:" << c2 << endl;
类型转换的过程:
1)把一个非布尔类型的算术值赋给布尔类型时,初始值为0则结果为false,反之为true
2)把一个布尔值赋给非布尔类型时,初始值为false则结果为0,反之则结果为1
3)把浮点数赋给整型时,会舍弃掉小数点部分,直接取整数。
4)把整数值赋给浮点类型,小数部分则补全为0,如果整数超出了浮点类型容量,可能出现精度损失。
5)给无符号类型赋值一个超出它范围的值时,初始值会对无符号类型表示的数值总数取模后的余数。
例如:unsigned char表示的时0~255,如果给它赋值 -1 ,其结果会是255
6)给带符号类型赋一个超出范围的值会导致程序崩溃或生产垃圾数据。
二,变量
1.变量的初始化
变量的定义,首先是类型说明符,后紧跟一个或多个变量名组成的列表,其中变量名以逗号分隔。最后以分号结束。
在定义一个变量时,还可以给它赋初值。
注:在C++中初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦掉,以一个新值来替换。
初始化的方式:
int solders = 0;
int solders = {0};
int solders{ 0 };
int solders(0);
2.变量的声明和定义
如果需要在多个文件中使用同一个变量就必须将声明和定义分离
变量能且只能被定义一次,但可以被多出声明。
如果想声明一个变量而非定义它,需要在变量前添加关键字extern,且不要显式地初始化变量。
extern int i; //声明而非定义
int j;//声明并定义
注:C++是一种静态类型语言,会在编译阶段检查类型。可以提前发现问题,减少不必要的调试。
3.标识符
由字母,数字和下划线组成,必须以字母或下划线开头,标识符长度没有限制,但不能使用C++关键字。
变量命名规范
1)标识符要能体现实际含义
2)变量名一般用小写字母,不要使用大写字母
3)定义的类名一般以大写字母开头
4)标识符应该由多个不同单词组成且有明显区分
5)不能出现连续的两个下划线
4.名字的作用域
一般指一个变量所在的括号的区域范围
分为:全局作用域,块作用域。
注:当块作用域和全局作用域出现相同变量时,优先使用块作用域。
//全局作用域变量i
int i = 20;
int main() {
//块作用域变量i
int i = 10;
int sum = 0;
for (int i = 0; i < 100; i++)
sum += i;
cout << sum << endl;
}
三,const限定符
使用const修饰的变量他的值不能被修改。
1.const的使用
例如:
const int pivot = 1024;
使用const 修饰一个常量,如果我们试图对他进行修改,编译器就会报错。因为cosnt对象一旦创建后其值就不能再改变,所以必须初始化。
使用一个非const对象给一个const对象赋值,其实现原理是把非const对象的值拷贝给const对象
例如:
double ab = 1024;
const int xy = ab;
float w = xy;
w = 2048;
ab = 4096;
cout << "ab:"<<ab<<"xy:" << xy << "w:" << w << endl;
在上述例子中,整个赋值过程仅时拷贝对象的值,不会改变原有对象。
2.const对象作用域
默认情况下const对象仅在文件内有效,编译器将在编译过程中把用到该变量的地方都替换成对于的常量对象的值。
例如:
const int max_cache_size = 1024;
int currentCacheSize() {
return 200;
}
int main() {
int cache_size = currentCacheSize();
if (cache_size > max_cache_size)
{
cout << "超出最大限制了,需要清理缓存了";
}
return 0;
}
在编译后,编译器会把代码中用到max_cache_size的地方全部替换成 1024。当多个文件内出现同名的const变量时,互相之间是独立的互不影响的,如果想要实现多个文件直接共享const对象,需要在变量声明或定义前添加extern关键字进行修饰。
extern const int max_cache_size = 1024;
注:如果想做多个文件直接共享const对象,必须在变量的定义之前添加extern关键字。
3.const的引用与指针
1)const与引用
把引用绑定到const对象上,不能用于修改它所绑定的对象。
const int ab = 1024;
const int& ac = ab;
2)const与指针
- 常量指针
指向常量的指针,不能用于改变其所指对象的值,要想存放常量对象的地址,只能使用指向常量的指针。
例如:
const double pi = 3.14;
const double* pr = π
*pr = 3.145;
当我们使用pr指针修改pi的值时,编译器就会报错,因为常量指针是不能修改所指对象的值。
注:常量指针也可以指向一个普通的变量。
例如:
int a = 20;
const int* pp = &a;
但是不能通过pp修改a的值。
不管是指向常量的指针或引用,他们都无法修改所指对象的值。
和常量引用一样,常量指针必须初始化,一旦初始化完成它的值就不能再改变
- 指针常量
指向常量的指针,即不变的是指针本身,而非指向的哪个值。
int ab = 0;
int* const cur = &ab;
- constexpr变量
变量声明为constexpr类型,让编译器来验证变量的值是否是一个常量表达式。
被constexpr修饰的函数会在编译时就可以计算其结果。
注:constexpr修饰的类型必须是字面值类型。
四,处理类型
1,类型别名
就相当于起一个外号一样,给系统类型或对象起一个别名,让负责的类型名称变得简单名了,易于理解和使用。
- typedef
typedef double screenSize;
typedef screenSize high, * p;
int main() {
high ab = 100;
return 0;
}
- using
using namespace std;
2,类型推断
- auto 类型推断
使用auto修饰的变量,编译器能替我们分析表达式所属的类型。
int a = 10, b = 20;
auto ab = a + b;
- decltype 类型指示符
从表达式的类型推断出要定义的变量的类型,但不想用该表达式的值初始化变量。
使用decltype可以选择并返回操作数的数据类型,编译器会分析表达式并得到它的类型,却不实际计算表达式的值。
int getAge() {
return 20;
}
int main() {
int value = 180;
decltype(getAge()) height = value;
return 0;
}
编译器并不实际调用函数getAge,而是当调用发生时getAge的返回值类型作为sum的类型。
相对于auto,decltype返回该变量的类型会包括顶层const和引用在内。
const int ci = 0, & cj = ci;
decltype(ci) x = 0;//x 的类型是const int
decltype(cj)y = x;//y的类型是const int&
注:decltype((variable))的结果永远是引用,而decltype结果只有当variable本身就是一个引用时才是引用。
五,导包注解
#define: 是一条预处理指令,用于定义一个预处理变量。
#endif:是一条预处理指令,用于结束一个#ifdef或#ifndef区域。
#ifdef:是一条预处理指令,用于判断给定的变量是否已经定义。
#ifndef:是一条预处理指令,用于判断给定的变量是否尚未定义。