C++入门基础知识

张开发
2026/4/15 4:47:12 15 分钟阅读

分享文章

C++入门基础知识
C关键字C98C总计63个关键字C语言32个关键字用到了再详细学习。命名空间为什么要引入命名空间用来解决名字冲突使得代码模块化、可读性更高什么是命名空间命名空间就是给代码加的「专属文件夹」用来避免名字冲突同时区分不同模块 / 库的代码是 C 组织代码的核心机制。命名空间的作用是什么解决名字冲突代码模块化、可读性更高命名空间的定义定义命名空间需要使用到namespace关键字后面跟命名空间的名字然后接一对{}即可{}中即为命名空间的成员。// bit是命名空间的名字一般开发中是用项目名字做命名空间名。namespace bit{// 命名空间中可以定义变量/函数/类型intrand10;intAdd(intleft,intright){returnleftright;}structNode{structNode*next;intval;};}//2. 命名空间可以嵌套//test.cppnamespaceN1{inta;intb;intAdd(intleft,intright){returnleftright;}namespaceN2{intc;intd;intSub(intleft,intright){returnleft-right;}}}//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。// ps一个工程中的test.h和上面test.cpp中两个N1会被合并成一个// test.hnamespaceN1{intMul(intleft,intright){returnleft*right;}}注意一个命名空间就定义了一个新的作用域命名空间中的所有内容都局限于该命名空间中命名空间怎么使用核心符号:: 是作用域解析符用来指定命名空间成员三种使用方法1.直接使用::号如命名空间名::变量名在命名空间中存在的2.在使用前使用using 命名空间名::变量名将变量解析出来就可以直接使用了3.将命名空间中的内容全部解析using namespace 命名空间名注意大型项目不要直接用 using namespace避免冲突优先用 命名空间::解析空间中的成员#includeiostreamusing namespace std;//c库中所以东西都是放在std命名空间中的intmain(){cout hello world endl;return0;}法二 #includeiostream//using namespace std;//c库中所以东西都是放在std命名空间中的intmain(){std::cout hello world std::endl;return0;}//是流插入运算符是流提取运算符缺省参数什么是缺省参数缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时如果没有指定实参则采用该形参的缺省值否则使用指定的实参。所以简称备胎参数。如下图运行结果缺省参数的分类全缺省参数注意传参调用时必须从左往右依次传参调用如下图中的操作会报错。半缺省参数注意缺省参数必须从左往右依次连续缺省否则会报如下错误。函数重载什么是函数重载函数重载是在同一作用域中声明几个功能类似的同名函数且函数参数不同其中参数不同又包含参数的类型不同参数个数不同和参数类型的顺序不同【如void Func1(int i, char ch); 和void Func(char ch, int i ); 构成函数重载】。对有没有返回值没有影响所以只有返回值不同时不能构成函数重载。c是如何支持函数重载的为什么c语言不支持函数重载C 支持函数重载而 C 语言不支持核心原因在于编译链接阶段的符号处理机制存在本质区别:程序从源码到可执行文件需要经过4个阶段list.h list.c test.c预处理生成list.i test.i头文件的展开/宏替换/条件编译/去掉注释编译生成list.s test.s检查语法生成汇编代码汇编生成list.o test.o汇编代码转成二进制的机器码链接将两个目标文件链接到一起编译时C 编译器在符号表生成的函数名就是原来的函数名同一函数链接时会发生冲突。所以c语言中无法支持重载.为支持重载C 编译器在编译时执行函数名修饰规则将函数名、参数类型、个数、顺序等信息编码为唯一的内部符号名。如 Linux g 下void add(int)会被修饰为_Z3addivoid add(double)会被修饰为_Z3addd修饰后的符号名完全不同链接器可精准区分。【同时不同编译器规则不同Linux g 采用_Z函数长度函数名类型首字母】引用什么是引用引用是给已经存在的变量取一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。引用的定义类型 引用变量名(对象名) 引用实体inta1;intraa;//ra是a的引用引用就是给已经存在的变量取一个别名此时a再取一个名称raintba;intcb;注意引用类型必须和引用实体是同种类型引用特性1. 引用在定义时必须初始化2. 一个变量可以有多个引用3. 引用一旦引用一个实体再不能引用其他实体如果引用了其地址不变若引用的变量有数值其原来的值会发生改变。地址变量值变为了2。常引用一constinta10;//int ra a; // 该语句编译时会出错a为常量就是说a是只读的b的类型是int是可读可写的所以不行。constintraa;// int b 10; // 该语句编译时会出错b为常量constintb10;二intc1;intdc;constintec;//ok的c是可读可写的e只可读总结引用取别名时变量访问的权限可以缩小不能放大//指针constint*cp1a;//int* p1 cp1;//不能属于权限的放大int*p2c;constint*cp2p2;//可以属于权限的缩小三inti1;doubledii;//隐式类型转换//double ri i;//不可行//floatt rf i;//不可行但是加const就可以如下图注意在变量之间没有权限缩小和放大的关系只有引用和指针才有。在实际静态/动态库中只会提供少量函数给程序用这些函数extern “C”,但其实一般提供tcmalloc和tcfree给外面用引用有哪些使用场景呢1.做参数作用做输出型参数提高运行效率voidSwap_c(int*p1,int*p2){inttmp*p1;*p1*p2;*p2tmp;}//c中使用引用做参数voidSwap_cpp(intr1,intr2){//r1对应a的别名r2对应b的别名inttmpr1;r1r2;r2tmp;}intmain(){inta1,b2;Swap_c(a,b);Swap_cpp(a,b);return0;}2.做返回值作用少创建一个临时对象提高程序效率//传值返回把函数里的变量拷贝一份给调用者这份拷贝就是临时变量用完就销毁。intCount1(){staticintn0;n;returnn;//会产生一个临时变量具有常性会多产生空间}//传引用返回把变量n的别名给调用者不用拷贝没有临时变量不会产生空间intCount2(){staticintn0;n;returnn;//直接返回n}intmain(){//int r1 Count1();//编译不通过constintr1Count1();intr2Count2();return0;}没有static时intAdd(inta,intb){intcab;returnc;}intmain(){constintretAdd(1,2);Add(3,4);coutAdd(1, 2) retendl;return0;}//结果如下运行结果有误原因是c是一个局部变量出了Add函数c就不在栈帧里了解决办法就是在c前加static修饰解决问题之后static修饰的变量在函数调用时值执行一次所以运行结果为3不变。总结一个函数要使用引用返回时返回变量出了函数的作用域还存在就可以使用引用返回否则不可以使用。内联函数为什么引入内联函数当我们频繁调用一个函数时需要创建栈帧是有消耗的因此为解决这个问题1c语言中使用宏函数但是其可读性比较差2c使用内联函数编译时C编译器会在调用内联函数的地方展开目的是以空间换时间但是函数没有地址。什么是内联函数以inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销提升程序运行的效率。//内联函数inlinevoidSwap(intx1,intx2){inttmpx1;x1x2;x2tmp;}intmain(){inta1,b2;Swap(a,b);return0;}如下图在反汇编中已经在调用函数的地方将函数展开使用内联函数不展开情况//内联函数inlinevoidSwap(intx1,intx2){inttmpx1;x1x2;x2tmp;//当内联函数中代码较多时就不展开了tmpx1;x1x2;x2tmp;tmpx1;x1x2;x2tmp;tmpx1;x1x2;x2tmp;tmpx1;x1x2;x2tmp;tmpx1;x1x2;x2tmp;}intmain(){inta1,b2;Swap(a,b);return0;}总结一般内联适用于小函数其次递归或者比较长的都不适合内联内联函数的特性inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率。一般内联适用于小函数其次递归或者比较长的都不适合内联inline不能声明和定义分离分离会导致链接错误。因为inline被展开就没有函数地址了链接就会找不到。auto关键字(C11)auto的作用推导出变量的数据类型由编译器在编译时期推导而得。注意使用auto定义变量时必须对其进行初始化在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。注意1.用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时则必须加。2.当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。3.auto不能做参数数组也不能用auto范围forc11特点写起来比较简洁使用案例//范围forintmain(){intarr[]{1,1,1,1,1,1};//要求将数据中的每一个值乘2再打印一遍//c11for(auto e:arr){//第二空只能是数组名不能是数组指针e*2;//并不改变数组中的值}for(auto e:arr){coute ;}coutendl;//改变数组中的值使用引用for(autoe:arr){e*2;}for(auto e:arr){coute ;}coutendl;}指针空值nullptr(C11)使用案例//指针空值nullptr(C11)voidfun(intn){cout整形endl;}voidfun(int*p){cout整形指针endl;}intmain(){//cint*p1NULL;//cint*p2nullptr;fun(0);fun(NULL);//预处理后fun(0)fun(nullptr);}

更多文章