【C++】入门基础 目录前言一、C基础知识1、C关键字C982、命名空间2.1命名空间的意义2.2命名空间的定义2.3命名空间的使用3、C输入输出关于 std::endl4、缺省参数5、函数重载6、引用6.1引用概念6.2引用的特性6.3 引用的使用6.4 const引用6.5指针和引用的关系7、inline8、nullptr总结前言C语言是结构化和模块化的编程语言适合处理较小规模的程序对于复杂、规模较大的问题需要高度的抽象和建模时C更加合适。C兼容C语言绝多数的语法C是在C语言的基础上容纳进去了面向对象编程思想并增加了许多有用的库以及编程范式等。C语言有一些语法的不足C对C语言设计不合理的地方进行了优化C既可以进行C语言的过程化程序设计又可以进行以抽象数据类型为特点的基于对象的程序设计还可以进行面向对象的程序设计。一、C基础知识1、C关键字C98C语言有32个关键字而C有63个。分类关键字控制语句相关if,else,switch,case,default,break,continue,goto,do,while,for,return数据类型相关int,char,float,double,void,bool,wchar_t,short,long,unsigned,signed存储类auto,register,static,extern,mutable,thread_local类型相关typedef,using,decltype,sizeof,alignas,alignof类和对象相关class,struct,union,enum,explicit,friend,this,virtual,override,final,public,protected,private,new,delete,const,volatile,constexpr,static_assert模板相关template,typename,class(在模板定义中)命名空间namespace,using异常处理try,catch,throw其他sizeof,nullptr,alignas,alignof预处理指令相关#define,#include,#if,#endif,#ifdef,#ifndef,#else,#elif,#pragma2、命名空间2.1命名空间的意义在C/C中变量、函数和后面要学到的类都是大量存在的这些变量、函数和类的名称将都存在于全局作用域中难免会导致冲突。使用命名空间的目的是对标识符的名称进行本地化以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的。例如#includestdio.hintrand10;intmain(){printf(%d\n,rand);return0;}上面定义了一个全局变量rand编译运行打印出rand的值。而当我们包含上头文件stdlib.h编译运行就会出现问题#includestdio.h#includestdlib.hintrand10;intmain(){printf(%d\n,rand);return0;}像上面这种情况编译运行就会报错因为rand是定义在头文件stdlib.h中的一个函数命名冲突了。C语言没办法解决这种命名冲突的问题所以C提出了namespace来解决。2.2命名空间的定义定义命名空间需要使用到namespace关键字后面跟命名空间的名字然后接一对{}即可{}中为命名空间的成员。命名空间域都是定义在全局的。例如namespaceyjz{//命名空间中可以定义变量、函数、类型intrand10;intAdd(intx,inty){returnxy;}structS{intn;charc;doubled;};}yjz是我名字的缩写一般开发中用项目名命名。上面是常规的命名空间定义命名空间还可以嵌套namespaceyjz{//命名空间中可以定义变量、函数、类型intrand10;intAdd(intx,inty){returnxy;}structS{intn;charc;doubled;};namespacejzy{intm;intSub(intx,inty){returnx-y;}}}namespace本质是定义出一个域这个域跟全局域各自独立不同的域可以定义同名变量。C有函数局部域、全局域、命名空间域、类域四个域。同一个工程中不同的.h和.cpp文件中允许存在多个相同名称的命名空间编译器最后会合并成一个。| 注意一个命名空间就定义了一个新的作用域命名空间中的所有内容都局限于该命名空间中。2.3命名空间的使用编译查找一个变量的声明/定义时默认只会在全局或局部查找不会到命名空间里面查找。使用命名空间有三种方式加命名空间名称及作用域限定符intmain(){printf(%d\n,yjz::rand);return0;}使用using将命名空间中某个成员引入usingyjz::jzy::m;intmain(){printf(%d\n,yjz::rand);printf(%d\n,m);return0;}使用using namespace命名空间名称引入usingnamespaceyjz;intmain(){printf(%d\n,yjz::rand);printf(%d\n,jzy::m);printf(%d\n,Add(3,5));return0;}3、C输入输出下面是我们学的第一条C语言代码#includestdio.hintmain(){printf(Hello world!\n);return0;}而同样的功能C是这样实现的#includeiostreamusingnamespacestd;intmain(){coutHello world!endl;return0;}std是C标准库的命名空间名C将标准库的定义实现都放到这个命名空间中。其中使用cout标准输出对象控制台和cin标准输入对象键盘时必须包含iostream头文件以及按命名空间使用方法使用stdcout和cin是全局的流对象endl其实是一个函数是特殊的C符号表示换行输出它们都包含在iostream头文件中是流插入运算符是流提取运算符C输入输出更方便可以自动识别变量类型不需要像C语言一样手动控制格式cout和cin分别是ostream和istream类型的对象和也涉及运算符重载等后续会详细介绍| 输出intmain(){intn1;charca;doubled3.14;coutn c dendl;return0;}| 输入intmain(){intn1;charca;doubled3.14;cinn;cincd;coutnendl;coutc dendl;return0;}这里要特别注意的是输入操作变量名前不加‘’符号这是不同于C语言的地方。| std命名空间的使用惯例std是C标准库的命名空间如何展开std使用更合理在日常练习中使用using namespace std即可方便using namespace std展开标准库就全部暴露出来了如果我们定义和库重名的类型、对象、函数就会产生冲突。我们日常练习代码量小基本不会出现这样的问题但项目中代码量大这样做很容易出现问题在项目开发中推荐使用std::cout这样指定命名空间或者using std::cout展开常用的库对象/类型等方式关于 std::endl本质std::endl \n换行 std::flush。注意很多人误以为换行就是刷新在终端下换行通常触发行缓冲从而看起来像刷新但在重定向到文件全缓冲时\n并不会刷新只有 std::flush 或 std::endl 才能真正强制写入滥用 std::endl 会严重影响性能频繁系统调用。4、缺省参数缺省参数是声明或定义函数时为函数的参数指定一个缺省值在调用函数时如果没有指定实参则采用该形参的缺省值否则使用指定的实参。voidFunc(intx5){coutxendl;}intmain(){Func();//没有传参时使用参数的默认值Func(10);//传参时使用指定的实参return0;}缺省参数分为全缺省和半缺省。全缺省参数voidFunc(intx1,inty2,intz3){coutx xendl;couty yendl;coutz zendl;}半缺省参数voidFunc(intx,inty,intz3){coutx xendl;couty yendl;coutz zendl;}| 注意半缺省参数必须从右往左依次给出不能间隔着给缺省参数不能在函数声明和定义中同时出现缺省值必须是常量或全局变量下面都是错误示范voidFunc(intx1,inty2,intz){coutx xendl;couty yendl;coutz zendl;}//test.hvoidFunc(intx1);//test.cvoidFunc(intx2){//}函数声明和定义分离时缺省参数不能在函数声明和定义中同时出现规定必须函数声明给缺省值。5、函数重载C支持在同一作用域中出现同名函数但是要求这些同名函数的形参不同可以是参数个数不同或者类型不同这样C函数就表现出了多态行为使用更加灵活。例如intAdd(intx,inty){returnxy;}doubleAdd(doublex,doubley){returnxy;}intmain(){coutAdd(1,1)endl;coutAdd(2.2,2.2)endl;return0;}提高了代码可读性通过使用相同的函数名称来执行相似的操作可以使代码更加简洁和易于理解。6、引用6.1引用概念引用不是新定义一个变量而是给已有的变量取一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。类型 引用别名 引用对象intmain(){inta10;intba;//给a取个别名叫ba;b;coutaendl;coutbendl;coutaendl;coutbendl;return0;}注意引用类型必须和引用实体是同类型的。6.2引用的特性引用在定义时必须初始化一个变量可以有多个引用引用一旦引用一个实体再不能引用其他实体6.3 引用的使用函数调用过程中传参和返回值没有了拷贝提高了效率引用传参和指针传参是类似的但是引用传参相对方便一些引用和指针在实践中相辅相成功能重叠各有特点互相不可替代C引用定义后不能改变指向例如voidSwap(intrx,intry){inttmprx;rxry;rytmp;}intmain(){intx1;inty2;coutx yendl;Swap(x,y);coutx yendl;return0;}6.4 const引用可以引用一个const对象但必须用const引用const引用也可以引用普通对象也就是对象的访问权限在引用过程中可以缩小但不能放大constinta10;//int* ra a;constintraa;//权限可以缩小但不能放大intb10;constintrbb;表达式相加、函数调用传值返回、类型转换等会产生临时对象C规定临时对象具有常性临时对象就是编译器需要一个空间暂存表达式的求职结果时临时创建的一个未命名的对象C把这个未命名对象叫做临时对象6.5指针和引用的关系语法概念上引用是给一个变量取别名不开空间指针是存储一个变量的地址要开空间引用在定义时必须初始化指针可以不初始化但是不推荐引用在初始化时引用一个对象后就不能再引用其他对象而指针可以改变指向对象引用可以直接访问指向对象指针需要解引用才能访问对象sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数4 / 8指针容易出现空指针和野指针的问题引用很少出现所以引用使用起来相对安全一些7、inline用inline修饰的函数叫做内联函数编译时C编译器会在调用的地方展开内联函数这样调用内联函数就不需要建立栈帧了可以提高效率inline对于编译器而言只是一个建议加了inline编译器也可以选择在调用的地方不展开不同编译器关于inline什么情况展开各不相同因为C没有规定这个。inline适用于频繁调用的短小函数对于递归函数和代码相对对一些的函数加上inline也会被编译器忽略成员函数默认是内联的允许同一个符号在多个编译单元存在多重定义规则放宽普通全局函数多个 cpp 定义同一个函数 → 链接报错inline 函数多个翻译单元拥有相同定义链接器合并为一份不报错C语言实现宏函数也会在预处理时替换展开但是宏函数实现很复杂容易出错且不方便调试C设计了inline的目的就是替代C语言的宏函数VS编译器debug版本下默认是不展开inline的这样方便调试debug版本想展开需要另外设置inline不建议声明和定义分离到两个文件分离会导致链接错误因为inline被展开就没有函数地址链接时会报错所以内敛函数建议直接放到.h文件8、nullptrNULL实际是一个宏C中NULL可能被定义为字面常量0或者C中被定义为无类型指针(void*)的常量不论采取何种定义在使用空值的指针时都不可避免的会遇到一些麻烦本想通过f(NULL)调用指针版本的f(int*)函数但是由于NULL被定义成0调用了f(int x)因此与程序的初衷相悖f((void*)NULL)调用会报错C11中引入nullptrnullptr是一种特殊类型的字面量它可以转换成任意其他类型的指针类型使用nullptr定义空指针可以避免类型转换的问题因为nullptr只能被隐式地转换为指针类型而不能被转换为整数类型总结作为在C语言基础之上发展出来的语言C对C语言设计不合理的地方做了很多优化使得程序设计更加模块化代码更容易组织和维护