C++复习录
1.命名空间namespace nn{ int a; }//名字空间指令 using namespace nn;//从这行代码开始,nn中的标识符在当前作用域可见(位于可见表) //名字空间声明 using nn::a;//从这行代码开始,nn中的a引入当前作用域(相当于定义,位于定义表)gcc/g++针对每个函数都和制作两张表,定义表和可见表。编译器先从定义表中找标识符,再到可见表中找。//名字空间别名 namespace nn_3=nn::nn1::nn2;2.函数重载#include iostream #include cstring using namespace std; // C++编译器(例如:g++),会更改我们书写的函数名 void foo( char* c, short s ) { // 完全匹配 cout "1. foo" endl; } void foo( const char* c, short s ) { // 常量转换 cout "2. foo" endl; } void foo( char* c, int s ) { // 升级转换 cout "3. foo" endl; } void foo( char* c, char s ) { // 标准转换 cout "4. foo" endl; } void foo( ... ) { // 省略号匹配(可变长参数) cout "5. foo" endl; } int main( void ) { char * c; short s; foo( c, s ); // _Z3fooPcs( c, s ); 普通方式调用重载关系的函数时,根据 实参的类型 来确定到底调用哪个foo void(*pfunc)( const char*, short ) = foo; // _Z3fooPKcs pfunc( c, s ); // 函数指针方式调用重载关系的函数时,根据 函数指针的类型 来确定到底调用哪个foo return 0; }调用优先级:完全匹配常量转换升级转换标准转换 自定义转换省略号匹配升级转换:没有信息损失的转换,小类型往大类型上转。标准转换:可能有信息的损失的转换,大类型往小类型上转。c++标准规定,函数都要换名。但是换名规则都不相同。linux:nm查看最终文件的符号表:nm a.out_Z:程序员自己定义的函数都这样开头3:定义函数名字的长度foo:自己定义的函数名字Pcs:形参表信息,P:pointer,c:char,Pc:char*,i:int,s:short,K:const,z:省略号。extern "C"{ int sum(){} int sub(){} }通过extern "C" 可以要求c++编译器按照c方式编译函数,即不做换名,当然也就无法重载。3.哑元函数只指定形参类型而不指定形参名称的函数,谓之哑元 保证函数的向下兼容。 形成函数的重载版本4.内联函数内联就是用函数已被编译好的二进制代码,替换对该函数的调用指令。内联在保证函数特性的同时,避免了函数调用的时间开销。inline关键字仅表示期望该函数被优化为内联,但是否适合内联则完全由编译器决定。稀少被调用的复杂函数和递归函数都不适合内联#include iostream using namespace std; // 内联函数 : 编译器的优化策略 void foo( int x ) { // 普通函数 cout "foo(int):" x endl; } inline void bar( int x ) { // 内联函数 cout "bar(int):" x endl; } #define PRINT(X) cout "PRINT(X):" X endl; int main( void ) { foo( 10 ); // 将此处 调用语句 替换为 跳转指令 foo( 20 ); // ... foo( 30 ); // ... bar( 10 ); // 将此处 调用语句 替换为 bar函数编译后产生的二进制指令集 bar( 20 ); // ... bar( 30 ); // ... PRINT(10); // 预编译阶段,做纯文本替换,正式编译阶段再将纯文本内容翻译为二进制指令集 PRINT(20); // ... PRINT(30); // ... return 0; }5.动态内存分配标准C库函数:malloc/freeC++:new/delete操作符int* pi = new int;//int告诉new申请几个字的操作符,返回值直接是指针 delete pi; int* pi = new int(100);//分配内存时同时初始化 //以数组方式new的也要以数组方式delete int* pi = new int [4]{1,2,3,4};//返回的永远是第一个元素的地址 delete[] pi;数组方式会多申请一块内存在第一个元素前,用来存数组个数,[]的作用是把多申请出来的内存释放掉。多维数组当一维数组看,new多维数组返回第一个元素的指针,即一维数组的指针。int (*p)[4] = new int[3][4]; delete[] p;//永远申请4个字节存放数组个数#include iostream #include cstdlib using namespace std; // 动态(堆)内存分配 int main( void ) { int* pm = (int*)malloc( 4 ); cout "*pm=" *pm endl; free( pm ); // 当这行代码执行结束,pm指向的堆内存已经被释放,pm变为野指针 pm = NULL; free( pm ); // 给free传递的参数为野指针,释放野指针后果未定义,释放空指针是安全的 int* pn = new int(100); cout "*pn=" *pn endl; delete pn; // 当这行代码执行结束,pn指向的堆内存已经被释放,pn变为野指针 pn = NULL; delete pn; // 给得了特传递的为野指针,delete野指针后果未定义,delete空指针是安全的 int* parr = new int[4]{ 10, 20, 30, 40 }; // 如果以数组方式new一块堆内存,返回的永远是 第一个元素的地址 for( int i=0; i4; i++ ) { cout parr[i] ' '; } cout endl; delete[] parr; // 数组方式new的,也要以数组方式delete int(*p)[4] = new int[3][4]; // 返回值是什么类型指针 delete[] p; try { new int[0xFFFFFFFF]; } catch( ... ) { } return 0; }new操作符申请内存失败,将抛出异常6.左值和右值左值:能够取地址的 右值:不能取地址的#include iostream using namespace std; // 左值 和 右值 int foo( ) { int m = 100; return m; } int main( void ) { // 函数的生命期 // 具名内存--能够取址--左值|非常左值(无const修饰) // |常左值 (有const修饰) int a = 10; a; a = 20; const int b = 10; b; // b = 20; // 语句级生命期 // 匿名内存--不能取址--右值|直接更改右值毫无意义(98/03标准给出的结论) // 10; // 10; // 10 = 20; /*|100|*/foo( ); // (1) 生成跳转指令 (2)分配一块内存空间 // foo( ); // foo( ) = 200; return 0; }7.引用前没有类型是取地址,前有类型是起别名。引用本身不占内存,对引用的所有操作都是在目标内存进行操作。引用必须初始化,且不能更换目标。int a = 10;int b=a;不存在引用的引用引用的常属性须和目标的常属性一致。const int e = 10; int f = e;//ERROR const int g = e;//OK可以限定更加严格int a = 10; const int b = a;//OKint r = 10;//ERROR,右值更改毫无意义所以不让改。 const int r = 10;//加const可以。 int r = foo();//ERROR,同理 const int r = foo();//OK带const的引用可以引用常左值,非常左值,右值。常引用即万能引用。引用可以延长右值的生命期。引用的生命周期不能长于目标引用型的返回值,从函数中返回引用,一定要保证在函数返回以后,该引用的目标依然有效。#include iostream using namespace std; // 引用 作为 函数的返回值 int g_value = 0; int foo( ) { // 非常引用型 返回值,通过其可以修改目标内存 return g_value; } const int fooo( ) { // 常引用型 返回值,通过其不可以修改目标内存 return g_value; } int bar( ) { static int s_value = 0; // 这句代码程序启动时就执行,而且只执行一次,不是每次调用bar函数执行 cout "s_value=" s_value endl; return s_value; } int hum( ) { int* pi = new int; return *pi; } int fun( int x ) { return x; } /* int boo( ) { int m = 8888; return m; // 返回局部变量的引用(别名) } */ int main( void ) { foo( ) = 100;//foo()是g_value的别名 cout "g_value=" g_value endl; fooo() = 6666;//error,不能改常引用型返回值 bar( ) = 200; bar( ); hum( ) = 300; int a_value = 0; fun( a_value ) = 400; cout "a_value=" a_value endl; // boo( ); return 0; }8.引用与指针的区别#include iostream using namespace std; // 引用 和 指针 的差别 int main( void ) { int a=10, b=20; int* pa = a; // 指针 可以随意变更其所指向的内存 pa = b; int ra = a; // 引用 不可以变更其所指向的内存 ra = b; pa = NULL; // 存在空指针 // ra = NULL; // error,不存在空引用 int** ppa = pa; // 存在二级指针 // int
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2499933.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!