1. 定义const对象
因为常量在定义后就不能被修改,所以在定义时必须进行初始化。
const int bufSize=512;
const int i; // error; i is uninitialized const
2. const 对象默认为文件中的局部变量
我们知道,如果我们在一个文件中定义了一个非const变量,如果我们想在另一个文件中使用这个变量,只需要在使用前添加extern 声明即可。
file1.cpp
int counter;
// file2.cpp
extern int counter;
++counter;
非const变量默认为extern。但是const对象默认为文件的局部变量,所以如果要使const变量可以在其他文件中使用,必须显式的将其指定为extern
// file1.cpp
extern const int counter=0;
// file2.cpp
extern const int counter;
for(int i=0;i<counter;i++)
{}
const引用
常见的错误:
1.普通的引用只在初始化的时候绑定对象(常量是错误的)。
2.将普通的引用绑定到const对象是不合法的。
3.const引用可以初始化为不同类型的对象或者初始化为右值。
#include <iostream>
using namespace std;
int main()
{
int a = 0;
const int bb = -1;
int &c = 3; //error 1
const int &d = 3;
int &ff = bb;// error 2
const int &e = a;
const int &f = bb;
const double &y = a; //3
return 0;
}
我们接着理解3,为什么const int &d=3是正确的呢?
对于int &d=3,如果我们进行d++,那么可以看作是3++,很明显是错误的。但是如果是const int &d=3,因为const只读,所以3++的情况不会出现,所以是允许的。
typedef:
定义:它在自己的作用域内给一个已经存在的类型一个别名。有四个常见的作用:
作用一:
typedef可以用来定义类型的同义词。
typedef int size;
size array[10];
作用二:
typedef 还可以掩饰复合类型,如指针和数组
如果我想定义多个大小为30的数组,不必这样一个个
char line[30]; char text[30];
只需要这样定义:
typedef char Line[30]; Line类型即代表了具有30个元素的字符数组
Line line,text即可等价上面的操作。
同样,可以像下面这样隐藏指针语法。
typedef char* pstar;
(#define dstar char*)
但是typedef并不是像define那样简单的替换,他是一个在作用域内有效的别名。
dstar pa,pb; //只是声明了一个指向字符变量的指针和一个字符变量
pstar pa,pb;// 声明了两个指向字符变量的指针
这里注意:
const pstar p;的含义与const dstar p是不同的。
第一个代表const指针,相当于 char * const p;其指针的指向不可更改;
第二个代表指向const对象的指针,p指向的内容不可更改。
作用三:
用在旧的c的代码中,用来帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,在大量使用的事是比较麻烦的。所以出现了
typedef struct node
{
int x;
int y;
}Point; Point a;
这种形式的写法,省略了struct。但是在c++中,这种写法不常见了。我们掌握这些是为了更好的阅读以前的代码。
作用四:
typedef & 复杂的变量声明
>1:int *(*a[5])(int, char*);
>2:void (*b[10]) (void (*)());
>3. doube(*)() (*pa)[9];
>1:int *(*a[5])(int, char*);
对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名(别名)替代变量名,然后把关键字typedef加在该语句的开头就行了。
//pFun是我们建的一个类型别名
typedef int *(*pFun)(int, char*);
//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
pFun a[5];
>2:void (*b[10]) (void (*)());
//首先为上面表达式蓝色部分声明一个新类型
typedef void (*pFunParam)();
//整体声明一个新类型
typedef void (*pFun)(pFunParam);
//使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());
pFun b[10];
>3. double(*)()[1] (*pa)[9][2] ;
//首先为上面表达式蓝色部分声明一个新类型
typedef double(*pFun)();
//整体声明一个新类型
typedef pFun (*pFunParam)[9];
//使用定义的新类型来声明对象,等价于double(*)()(*pa)[9];
pFunParam pa;
pa是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是“doube(*)()”--也即一个指针,指向一个函数,函数参数为空,返回值是“double”。
#include <iostream>
using namespace std;
char s[2]={'a','b'};
int f(int x)
{
x+=5;
return x;
}
int* ff(int x)
{
x+=1;
return &x;
}
void ff2(int x)
{
cout << "已经执行" << endl;
}
typedef char* pstar;
int main()
{
int (*p)(int x); //声明一个函数指针
void (*a[1])(int) = {ff2}; // 定义一个函数指针数组
(*a[0])(1);// 调用---result :已经执行
p=f;
cout<<(*p)(1)<<endl; // result: 6
cout<<*(ff(2))<<endl;// result 3
const pstar nm=s;
return 0;
}
另外,容易出错的一点是typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; //不可行
编译将失败,会提示“指定了一个以上的存储类”