常量
c++提供了常量的概念, const就是为了直接表述"不变化的值"这样一个概念.因为不允许赋值,常量就必须初始化.
const int model = 10;//model是个常量
const int v[] = {1, 2, 3, 4};//v[i]是个常量
const int x;//错误:没有初始化
编译器可以靠多种方式利用一个对象是常量的这一性质.例如,对于常量的初始式是常量表达式;如果是这样,那么这个常量就可以在编译时求值.进一步说,如果编译器知道了某const的所有使用,它甚至可以不为该const分配空间.
const int c1 = 1;//不需要分配空间
const int c2 = 2;
const int c3 = my_f(3);//编译时不知道c3的值, 需要分配空间
extern const int c4;//编译时不知道c4的值, 需要分配空间
const int* p = &c2;//因为c2的地址被取用,所以c2需要分配空间
const最常见的用途就是作为数组的界或者作为分情况标号
const int a = 42;
const int b = 99;
const int max = 128;
int v[max];
void f(int i) {
switch (i) {
case a: //...
break;
case b: //...
break;
default:
break;
}
}
指针和常量
需要记住的是只有*const的声明运算符,而没有const*的声明运算符, 所以const出现在*之前都修饰的是基础类型(如:int,double等)
char* const p1; //到char的const指针
char const* p2; //到const char的指针
const char* p3; //到const char的指针
引用
一个引用就是某对象的另一个名字.引用的主要用途是为了描述函数的参数和返回类型.特别是函数的重载.
另外,对一个const T&初始式不必是一个左值,甚至类型可以不是T
double& dr = 1;//错误 要求左值
const double& cdr = 1;//ok
//对后一个初始化的解释是
double temp = double(1);//首先创建一个临时变量
cosnt double& cdr = temp;//将这个临时变量作为cdr的初始式
指向void的指针
一个指向任何对象类型的指针都可以赋值给类型为void*的变量,void*可以赋值给另一个void*,两个void*可以比较相等与否,而且可以显示地将void*转换到另一个类型。其他操作都是不安全的,因为编译器不知道实际被指的是哪种对象。因此,对void*做其他任何操作都将引起编译错误。要使用void*,我们就必须显式地将它转换到某个指向特定类型的指针。
void f(int* pi) {
void* pv = pi; //可以;从int*到void*的隐式转换式
*pv; //错误,void*不能间接引用
pv++; //错误,void*不能增量(不知道被值对象的大小)
int* pi2 = static_cast<int*>(pv); //显示转换为int*
double* pd1 = pv; //错误
double* pd2 = pi; //错误
double* pd3 = static_cast<double*>(pv); //不安全
}
到函数的指针和成员的指针都不能赋给void*
结构
数组是相同类型的元素的一个聚集。一个struct则是任意类型元素的一个聚集
struct address {
const char* name;
long int number;
const char* street;
const char* town;
char state[2];
long zip;
}; //address是定义的新类型的名字(就跟int一样)
void f() {//赋值方式
address jd;
jd.name = "Morty";
jd.number = 61;
address bb = {"Morty", 61, "South st", "NewYork", {'N', 'J'}, 7974};
}
void print_addr(address* p) {//通过指针间接访问
std::cout << p->name << (*p).name;
}
address s(address next) {//作为函数的返回类型
return next;
}
struct类型名字出现之后立马就可以使用了,不必等到完整的声明之后。
struct Link {
Link* p;
Link* n;
};
在完整声明被看到之前,不能去声明这个结构类型的新对象
struct Link {
Link labs; //错误
};
想允许两个以上的结构类型互相引用,我们可以先将一个名字声明为结构的名字。
struct List;
struct Link {
Link* pre;
Link* suc;
List* member_of;
};
struct List {
Link* head;
};
两个结构总是不同的类型,即使它们有着相同的成员
struct S1 {
int a;
};
struct S2 {
int a;
};
S1 x;
S2 y = x;//错误,类型不匹配