nullptr
C++11中新加入了nullptr来初始化空指针。nullptr是一种特殊类型的字面值,它可以被转换成任意其他类型的指针。现在应当尽量使用nullptr而不是NULL来初始化空指针。
int *a = nullptr;
char *c = nullptr;
变量的声明与定义
变量能且只能被定义一次,但可以被多次声明。
extern double pi = 3.14; // 定义
int main(void)
{
extern int a; // 声明
int b; // 定义
extern double f = 0.01; // 错误:不允许对外部变量的局部声明使用初始值设定项(初始化)
}
关于引用
引用本身不是一个对象,定义引用时必须初始化,并且一旦定义后就无法改变其指向。
int a = 0;
int b = 1;
int &ref = a;
ref = b; // 该语句其实等价于a=b,并非将ref改成b的引用,引用一旦定义就无法改变其指向。
指向常量的指针和指针常量
代码中cptr是指向const double类型的指针即指向常量的指针。所以*cptr不能更改,但cptr本身可以更改,由于pi是并非const double,所以直接更改pi也是合法的。
double pi = 3.14;
const double *cptr = π
pi = 3.1; // 合法
cptr = 0; // 合法
*cptr = 0; // 非法
代码中pip是指向const double类型的const指针,即指向常量的指针常量。pip本身和*pip都是不可修改的。而currErr是指针常量,不能修改currErr但能修改currErr所指向的errNumb的值。
int errNumb = 0;
int *const currErr = &errNumb;
const double pi = 3.14;
const double *const pip = π
constexpr常量表达式
C++11规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = size(); // 非法,只有当size()是一个constexpr函数时正确。
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关。
这段代码中p和q的类型相差甚远,p是一个指向常量的指针,q是一个指针常量。
const int *p = nullptr;
constexpr int *q = nullptr;
用constexpr修饰的指针指向的变量的地址必须是常量,比如放置在全局存储区的const int i,如果将const int i = 0这句话放在函数体内部就会报错,因为i的地址实在栈上的,会发生变化,p的值也就无法成为常量表达式了。
const int i = 0;
int main(void)
{
constexpr const int *p = &i;
}
类型别名
C++11中有一种给类型取别名的新方法using。wages和wages2和double是等价的。
typedef double wages;
using wages2 = double;
wages d1;
wages2 d2;
需要特别注意的是以下这种情况,cstr和cstr2的数据类型并不相同,cstr2是指向const char对象的指针,而cstr却是指向char对象的指针常量。应当把pstring看作一个整体处理而非把他的别名替换回去处理。
typedef char *pstring;
const pstring cstr = 0;
const pstring *ps;
const char *cstr2 = 0;
decltype
decltype通过推断表达式值的类型来推断要定义的变量类型,需要特别注意的是下面代码中*p对应的是int&型而非int型。
const int ci = 0, &cj = ci;
decltype(ci) x = 0;
decltype(cj) y = x;
decltype(cj) z; //错误:z是一个引用,必须初始化
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; //正确,b是int类型
decltype(*p) c; // 错误,*p是解引用,其得到的数据类型是引用型,必须初始化。可以理解为*p是i的别名,所以*p也是引用类型。
auto d = *p; // 正确,d是int型,要和上面的区分开来。
decltype((i)) e; // 错误,(i)会让编译器认为是一个表达式,因此是int&类型,必须初始化。