26.在C++11标准中生成空指针最好使用int *p = nullptr;当你不清楚指针该指向何处时,可以把它初始化为控制针,这样程序就能检测并指导它没有指向任何具体的对象了。
27.void *p是一种特殊的指针类型,可用于存放任意对象的地址,我们不能直接操作void *指针所指的对象,因为我们不知道这个对象到底的是什么类型,也就无法确定能在这个对象上做哪些操作。就是不能以*p的形式对它所指object进行操作。
//const的引用
32.对常量对象的引用必须由一个常量引用定义(const int i =1024; const int &re = i;),re无法修改,因为i是一个常量对象。
//初始化和对const的引用
33.初始化常量引用时,允许任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。如(int i =42;const int &re = i;这里和前面的引用不同,普通引用必须左右两边对象类型相同,而这里一边是const int 一边是Int)
34.这样的引用也是不可以改变的,re = 1024;是错误的(因为re本身不是对象,它其实就代表了它所引用的const)。这里应该是把int 转换成了const int.如果要改变i的值,只要不是通过re就可以改变。
//指针和const
35.指向const的指针和const指针:指向const的指针const int *p =&i;(const int i = 1024;)因为它指向的是一个const,所以这个const不能被改变(*p =202;是错误的,这里试图改变i的值),但是p本身也是一个对象,它的值(i的地址)是可以改变的(p=293810;是对的);而const指针(int a =42;int *const p = &a;),此时p是一个常量(所以必须初始化),它的值是永远不变的,但是a的值可以通过其他方式改变。
//顶层const
36.顶层const为本身就是一个const,底层const为指向const的指针或者引用。只有和const有关才有顶层const和底层const的概念,int a = 3;就不包含const元素,既不是顶层const也不是底层const。
//constexpr常量表达式
37.constexpr只值不会改变并且在编译过程就能得到计算结果的表达式。const int i=10;i是常量表达式,const int sz = get_size(); sz不是常量表达式,因为它的具体值直到运行时才能获得。
38.constexpr表示这玩意儿在编译期就可以算出来(前提是为了算出它所依赖的东西也是在编译期可以算出来的)。
39.一个constexpr指针的初始值必须是nullptr或0,或者是存储于某个固定地址中的对象。
40.constexpr把它锁定义的对象置为了顶层const(本身为一个const)。
41.constexpr指针不能指向函数体内定义的变量,因为他们并非存放在固定地址中,相反,定义于所有函数体之外的对象其地址固定不变,能用来初始化constexpr指针。
//处理类型
//类型别名
42.它是某种类型的同义词,便于理解。
43.有两种方法可以定义类型别名:
(1)关键字typedef
typedef double wages;//wages 是double的别名
typedef wages base,*p;//base是double的同义词,p是double*的同义词
可以把这个语句看成一个定义语句,typedef为基本数据类型,double为类型(相当于变量),wages为类型别名(变量初始化)。
(2)在C++11新标准中,可以使用“别名声明(alias declaration)”
using SI = Sales_item; //SI是Sales_item的同义词
using为关键字,此声明语句把等号左边的定义为右边类型的别名。
44.当类型别名指代的是复合类型时,把它用到声明语句时要十分小心:
typedef char *pstring; //pstring 是 char*的别名,即指向字符的指针
const pstring cstr=0; // 如果把“指向字符的”这个修饰词去掉,那const pstring就是常量 // 指针的意思,所以cstr就是指向char的常量指针
const pstring *ps; //指向指向char的常量指针的指针
//auto类型说明符
45.要把表达式的值赋值给变量就要知道表达式的数据类型,然而这并非那容易。C++11引入了auto类型说明符,它可以让编译器通过初始值来推算变量的类型。auto 定义的变量必须有初始值auto item = val1 + val2;//由val1+val2的结果来确定item的类型。
46.auto也能在一条语句中声明多个变量,不过要求所有变量的初始基本数据类型都一样。
auto i = 0 ,*p=&i;//正确,p为整型指针
auto sz = 0 ,pi=3.14;//错误,sz和pi的基本数据类型不一样。
47.auto一般会忽略顶层const,同时底层const会被保留
int i = 0;
const int ci = i ,&cr=ci;
auto b = ci; //b是一个整数(ci的顶层const(本身是常量)特性被忽略掉了
auto d = &i; //d 是一个整形指针(整数的地址就是指向整数的指针)
auto e = &ci; //e是一个指向整数常量(获取的是const int ci 的地址)的指针
const auto f = ci ; //f为 const int (从右到左理解)
48.如果引用的类型为auto,原来初始化的规则仍适用
auto &g = ci; //g是一个整型常量引用,绑定到ci(顶层const特质仍然存在)
//decltype类型指示符
49.希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。decltype(f()) sum = x; // sum的类型就是函数f的返回类型。
50.如果decltype使用的表达式是一个变量,则它返回该变量的类型(包括顶层const和引用在内):
const int ci=0,&cj=ci;
decltype(ci) x = 0;//x的类型为const int
decltype(cj) y = x; //y的类型是const int&,y绑定到x ,在这里cj是作为引用本身出现,而其他情况是作为它所引用的变量ci出现。
如果想让decltype返回的结果是引用所指的类型,可以用decltype(re+0)
51.int *p = &i; decltype(*p) 返回的类型是 int&,因为可以通过*p=10;修改i的值,有一种引用的关系。
52. decltype((variable)) 双层括号返回的类型永远都是引用,而decltype(variable)一层括号则根据variable的类型来确定返回类型。
//自定义数据结构
53.每一个类的对象都包含所有类的成员。
54.C++11新标准规定可以为数据成员提供一个类内初始值。没有初始值的成员将被默认初始化。
55.为了确保各个文件中类的定义一致,类通常被定义在头文件中,而且类所在头文件的名字应与类的名字一样。(把Sales_data类定义在名为Sales_data.h的头文件中)
56.确保头文件多次包含仍能安全工作的常用技术是预处理器(preprocessor),预处理器实在编译之前执行一段程序。
57.还有一项预处理功能是头文件保护符,头文件保护符依赖于预处理变量。
#ifdef SALES_DATA_H //#ifdef当且仅当变量已定义时为真,#ifndef当且仅当未定义为真
#define SALES_DATA_H //#define把一个名字设定为预处理变量
#include<string>//为了避免与程序中的其他实体发生名字冲突,一般把预处理变量的名字全部大写
struct Sales_data {
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
#endif //一旦上述检查为这,则执行后续操作指导遇到#endif指令为止