1. The concept of Compound Types:
A compound type is a type that is defined in terms of another type, C++ has several compound types, two of which---references and pointers.
declarations consist of a type followed by a list of variable names----A declaration is a base type followed by a list of declarators. Each declarator names a variable and gives the variable a type that is related to the base type.
references and pointers in a declaration are called modifier.
2. references:
引用是一个变量的别名,没有地址,因此,不能定义引用的引用,如: int&& p = ....; 是不能表示引用的引用的,但是它却是另一个compound type, 叫做rvalue reference(右值引用)
一旦定义引用后,该引用的使用就相当于在使用原变量了,只是名字换了而已.
3. Pointers:
引用没有地址,因此,不能定义引用的指针,(int& *p)
指针的类型必须和所指向的变量名一致,除非是void* 类型
nullptr: 没有初始化的指针应该在C++11中应该赋值为nullptr, 表示没有指向任何对象
4. Compound Types:
1. Pointers to Pointers:
指针也是变量,所以可以定义指针的指针,但类型必须保持一致
2. references to pointers:
指针是变量,所以可以定义指针的引用.
int i = 1, *pi = &i;
int* &rp = pi;
在上面的定义中,我们从右往左读,首先,rp是一个引用,然后是一个int*,表示是一个int*的引用,相当于给pi取了一个别名。
5. const Qualifier:
1. const 在definition的时候必须被初始化.
2. By Default, const Objects are local to file.即,const默认是只能在本地使用的,不像其他的类型:在其他文件中可以用extern来使用,但是在const中,一旦被初始化,编译器会在本地每个使用该const的地方替换为对应的值,所以不能在其他文件中使用。
3. 如何在其他文件中使用const呢?可以在definition的时候加上extern,如:extern const int a = 2; 表示该变量可以在其他文件中使用,然后如果想在其他文件中使用,只需要declaration就ok了,比如extern const int a;就可以使用了。
4. 需要注意的是,无论是const 还是 非const , 使用extern的时候都不能在函数中进行初始化。
6. references to const
1. 我们不能用一个非const的引用对一个const类型的变量进行引用(如:const int a = 10; int& c = a是错误的, 必须是const int& c = a才是正确的,因为a本身是不可改变的,所以也不能通过c来进行改变)
2. 当我们定义了一个const的引用:如const int &a, 的时候,我们可以用任何可以强制转化为const的表达式对a进行初始化,也就是说,我们可以定义一个const 的引用,指向一个非const的变量(即使类型不同),一个literal, 或者任何可以强制转化为const的表达式。如:
double b = 3.14;
const int &a = b;
上面的定义中,我们以前说过,引用和被引用的变量之间的类型必须一样,但是,这里有例外(以后还有另一个例外),就是当我们初始化一个const的引用的时候,那么上面的定义发生了什么呢?我们知道,a是一个指向int型的引用,为了保证这一点,编译器做了下面的事情来进行强制转化:
7. pointers to const( low-level const) AND const pointers( top-level const )const int temp = b;
const int& a = temp;
编译器创建了一个临时的没有名字的变量,并且把这个变量和a进行绑定,考虑如果a不是const的话,那么a是绑定了一个编译器创建的空的变量,那么改变它是没有意义的,和我们想改变的结果b是不一样的。
1.pointers to const (直接用例子来说明了):
const double a = 3.14;
double b = 3.14;
double *test = &a; //错误
const double* p = &a;
p = &b; //正确:pointers to const 指的是所指向的那个变量的值不能改变,但是指针本身可以改变
*p = 2.2; //错误,p是一个指向const 的指针,所以不能改变所指向的值.
2. const pointers
int a = 0, b = 0;
int *const p = &a; //p必须被初始化,并且只能永远指向a,不能改变。
*p = 2;
p = &b; //错误
const double pi = 3.14159;
const double *const ppi = π//ppi是一个指向const的const pointer.
8. constexpr and literals types
constexpr是c++11新标准,为什么要定义它呢?有时候我们定义一个const类型的变量,并且希望初始化它的是一个常量表达式(const expression, 即能够在编译的时候就确定他的值), 可是有时候我们并不知道初始化它的到底是不是常量表达式,比如:const int sz = get_size(), 我们并不知道get_size()这个函数是否是一个const expression, 所以c++11引入了constexpr, 让编译器来帮我们检查,constexpr int a = 20*2*a*b; 它保证了,初始化a的一定是一个const expression。
由于constant expression 是在编译的时候被确定,所以能用constexpr修饰的类型只限于literal types(因为他们足够简单,能够有literal values), 常见的literal types有:arithmetic, reference, pointer, 不是literal types的有:class, library IO, string. 所以不能定义这些类型的constexpr,
即使我们能定义pointer and reference为constexpr, 但是对他们的初始化确实很有限制的,比如:我们能用nullptr和0 literal来初始化constexpr pointer, 我们也能指向一个有固定地址的变量,然而,在函数内定义的变量一般都没有固定的地址,所以我们只能用在函数体外定义的变量(函数体外的变量有固定地址) 来初始化constexpr pointer.
9. Pointers and constexpr
constexpr 和 const 不一样,constexpr是top-level const, 而const是low-level const
const int *p = nullptr; // p is a pointer to a const int
constexpr int *q = nullptr; // q is a const pointer to int.
constexpr int *np = nullptr; //np is a const pointer to int that is null
int j = 0;
constexpr int i = 42; // type of i is const int
// i and j must be defined outside any function
constexpr const int *p = &i; // p is a constant pointer to const int i
constexpr int *p1 = &j; // p1 is a constant pointer to the int j;