1、引用 • 可以把引用看成一种隐式的指针,它可以免除获取变量地址和对指针解除引用的麻烦;也可以把引用看作是原变量的另一个名字。 • 除了类里面的引用数据成员以外,引用变量必须在创建时就进行初始化,否则出错。类的引用数据成员必须使用初始化参数列表进行初始化。 • 除非引用指向一个const值,否则不能创建指向未命名值的引用: int& unnamedRef=5; //DOES NOT COMPLIE const int& unnamedRef=5; //Works as expected • 引用总是指向初始化时指定的那个变量,一旦创建引用,就不可再修改。 • 指针引用和引用指针 int* intP; int*& ptrRef=intP; ptrRef=new int; *ptrRef=5; //*intP=5 注意:取一个变量的引用的地址和取该变量的地址结果一样。 不能声明指向引用的引用,也不能声明引用指针(指向引用的指针): int x=3; int& xRef=x; int&& xDoubleRef=xRef; //DOES NOT COMPILE int&* refPtr=&xRef; //DOES NOT COMPLIE • 函数参数是一个引用,但是传递给该函数的却是一个指针 在这种情况下,可以简单的先对指针进行解引用,这样得到指针指向的变量,然后编译器会用这个变量来初始化引用。 Swap(int& x,int& y); int x=6;int y=9; int* xp=&x; int* yp=&y; Swap(*xp,*yp); • 使用引用主要是考虑“效率(不会产生中间变量)”和“正确性(避免因为浅拷贝出现问题)” • 使用指针还是引用 引用可以使代码更加简洁,因为指针要对其进行解引用; 引用也比指针安全,不存在空引用; 对象引用也支持多态性; 原则:除非需要动态分配内存或者要在其他地方改变或释放指针指向的值,否则,应该使用引用而不是指针。 2、const • 指名其修饰对内容保持不变,用于:标识变量和标识方法 • cosnt修饰变量 1、代替#define来定义常量 2、const int* p=NULL 《==》int const* p=NULL const应用于紧挨着const左侧的第一项。 3、const int&和int const&是等价的;C++不允许使用const声明引用,因为引用本身就是常量 int z;int& const refInt=z; //WRONG!!! • const方法 在类里面声明方法使用const,可用于防止对数据成员的修改 3、static static有三种不相关的用法: • static数据成员和方法,表示该成员或方法归类所有,所有对象共用一个; • static链接 先了解一下C++中链接linkage的概念。C++中每个源文件是独立编译的,得到的对象文件要链接在一起。C++源文件中的每个名字,包括 函数和全局变量,都有一个链接,可能是内部internal链接,也可能是外部external链接。外部链接是指,对于其他源文件,这个名字是可用的。内部链接(也称为静态链接static linkage)是指,对于其他源文件,这个名字不可用。函数和全局变量默认都是外部链接。但是,可以在声明前面加上static,来指定为内部/静态链接。 比如: //FirstFile.cpp void f(); //prototype declare int main() { f(); return 0; } //AnotherFile.cpp void f(); void f() { cout<<"f()/n"; } ... 因为函数和全局变量默认为外部链接,所以,在FirstFile.cpp里面对f()的调用成功; 但是如果把AnotherFile.cpp中的f()声明加上static: static void f(); 这时,在FirstFile.cpp里面就不再可以调用。 C++委员会已经意识到static的意思太过丰富,所以,不建议使用static,来声明内部链接。 相同的方法:匿名命名空间anonymous namespace来保证函数或全局变量为内部链接: //AnotherFile.cpp namespace { void f(); void f() { cout<<"f()/n"; } } ... 使用匿名命名空间以后,就只能在该文件中中访问。 与static相反的就是extern关键字了。 注意,把一个名字指定为extern时,编译器会把它当作声明而不是定义。对于变量来说,这意味着编译器不会给变量分配空间。必须提供没有extern的变量定义,或函数定义。 如: //another.c extern int x; //若写成extern int x=3,编译器会有warning int x=3; //first.c #include <stdio.h> extern int x; //如果没有这一句会提示x未定义 int main( ) { printf("%d/n",x ); return 0; } 编译命令: gcc -Wall first.c another.c -o first 注意:在实际的项目中不建议使用全局变量,具有迷惑性。 • 函数中的static 用于创建局部变量,通常用于记录是否已经为一个函数进行特定的初始化。 void perfrom( ) { static bool inited=false; if( !inited ) { //perform initialization inited=true; } ... } • 不同文件中非局部变量的初始化顺序并不确定 程序中所有的全局变量和static类数据成员都是在main之前初始化的。不同文件中非局部变量的初始化顺序并不确定,所以当不同文件中对非局部变量的初始化需要另外的非局部变量时,可能会出现依赖死锁。 4、类型转换 • const_cast用于删除常量属性 • static_cast用于显示的完成C++语言直接支持的转换,如int/float/char;static_cast还可以用于在继承层次结构中完成向下类型强制转换。 • reinterpret_cast比static_cast更强,但安全性较低。满足以下类型转换: 按照C++类型规则来说,从理论上讲这种转换是不允许的,但是在某种场合下它们对程序员可能很有意义。例如,可以把一种指针或引用转换成另外的一种指针或引用,即使在继承层次不相关也可以;还可以把指针转换成int,或者int转换成指针。在使用reinterpret_cast的时候要格外小心,因为它会把原始的位bit重新解释为不同的类型,却不会进行类型检查。 • dynamic_cast进行转换时,会进行运行时类型检查,运行时类型信息是存储在对象的vtable里面的。因此使用dynamic_cast,类必须至少有一个虚函数。