//1.一条声明语句由一个基本数据类型和紧随其后的一个声明符列表组成。每个声明符命名了一个变量并指定了该变量为与基本数据类型有关的某种类型。在同一条声明语句中,基本数据类型是相同的,但是声明符不一定相同。 // 基本类型:是类型说明符,可用const修饰,在声明语句中位于声明符之前。基本类型提供了最常见的数据类型,以此基础构建声明符。 // 声明符:是声明的一部分,包括被定义对象的名字和类型修饰符。其中类型修饰符(比如const,* ,&等)可有可无。 int value0 = 0; //此定义语句中, int为基本数据类型, value0为声明符。此声明语句的结果是将声明符value指定为int类型。 int *pvalue0, value1; //在此定义语句中,定义了2个类型不同的变量。pvalue0为int*类型,其类型修饰符*是声明符的一部分, value1为int类型,它们的基本数据类型都是int。 //2.引用:为对象起了另一个名字,引用必须初始化,引用无法重新绑定到另一个对象上。引用本身不是一个对象。 // 引用类型要和其绑定的对象严格匹配,但是有两个例外:1.在初始化常量引用的时候,允许使用任意能转化为该引用类型的表达式作为初始值。2.父类引用能接受子类对象。 double data0 = 3.14; const int &data1 = data0; //合法,但data1和data0的地址不同 //3.指针:是指向另一种类型的复合类型。其本身就是一个对象。 void*指针是一种特殊的指针,可以用于存放任意对象的地址,不能对void*指针进行解引用。 // 指针类型必须和所指对象严格匹配,但是有两个例外:1.允许一个指向常量的指针指向一个非常量对象。2.父类指针能指向子类对象。 int number = 0; const int *pNumber0 = &number; int *const pNumber1 = &number; //离pNumber1最近的符号是const,意味着pNumber1本身是一个常量,其类型由声明符的其余部分决定。 //4.默认情况下const对象被设定为文件内有效。当多个文件中出现了同名const变量,等同于在不同文件中分别定义了这些独立的变量。若在头文件定义了一个const变量,那么多个包含此头文件的源文件中都将定义自己的独立的const变量。 // 如希望将const变量进行文件间共享,则在一个源文件中进行定义,在头文件中进行extern声明即可,那么所有包含此头文件的源文件都将共享一个const变量。 // const分为顶层const和底层const。顶层const可以表示任意的对象是常量,而底层const表示指针所指的对象是常量。由于引用不是对象,所以引用类型的const都是底层const // 在执行对象拷贝的时候,常量是顶层const还是底层const有明显区别。其中,顶层const不受影响。另一方面,底层const对象执行拷贝操作的时候,要求拷入和拷出的对象必须具有相同的底层const资格或者两个对象的数据类型能够转换。 // const是一种类型修饰符 const int *p0 = nullptr; //此处的const是底层const int *const p1 = nullptr; //此处的const是顶层const const int count = 0; //此处的const是顶层const //5.类型别名:使用关键字typedef。 typedef int* pint; int nData = 0; const pint pData = &nData; //等价于: int *const pData = &nData; 注意点:声明中用到了pint,其基本数据类型是指针,若写成 const int *pData = &nData;则其基本数据类型是int, *变成了声明符的一部分。 //pData = nullptr; //错误 error C3892: “pData”: 不能给常量赋值 typedef class B { }b; //b为B的别名 //6.auto:让编译器通过初始值来推断变量的类型。显然,auto定义的变量必须具有初始值,且其基本类型必须相同。 // auto在下列几种情况下推断出的类型与其初始值并不完全一样,编译器适当的改变结果类型使其更加符合初始化规则 // A:编译器以引用对象的类型作为auto的类型。 // B:auto会忽略顶层const并保留底层const // C:auto会将函数名转为对应函数指针类型 // D:auto会将数组名转为对应指针类型 //7.decltype:希望从表达式中推断出要定义的变量的类型,但是不想用该表达式的值来初始化变量。在此过程中,只得到表达式的类型而不实际计算表达式的值。 // decltype不会执行auto中编译器执行的转换。 // 如果decltype使用的表达式不是一个变量,则decltype返回表达式对应的类型。如果表达式的求值结果是左值,则decltype作用于该表达式(不是一个变量)得到一个引用类型。 int nNumber0 = 10; int *pnNumber0 = &nNumber0; decltype (nNumber0) nNumber1; //nNumber1为int类型 decltype (pnNumber0) nNumber2; //nNumber2为int*类型 decltype ((nNumber0)) nNumber3 = nNumber0; //nNumber3为int&类型 decltype (*pnNumber0) nNumber4 = nNumber0; //nNumber4为int&类型 //8.结构体和类的类体的后面都可以跟其对象的定义 class A { } a; //a为类A的一个对象 //9.当预处理器看到#include标记时,就会用指定的头文件的内容代替#include // 通常使用#ifdef #endif 来防止重复包含。 #ifdef #endif 都是一条预处理指定 // 预处理变量无视C++语言中关于作用域的限制 #define 是一条预处理指令,用于定义一个预处理变量 // 在程序编译之前,预处理器负责将程序中的预处理变量替换为它的真实值
时间: 2024-09-29 19:27:34