当前位置: 首页 > news >正文

企业微信网站开发文档前端可以做什么毕业设计

企业微信网站开发文档,前端可以做什么毕业设计,商务网站制作语言基础,公司英文网站多少钱目录 命名空间 1、命名空间的定义 2、命名空间的使用 1、加名空间名称和作用域限定符 2、使用using namespace 命名空间引入 3、使用using将命名空间中某个成员引入 C的输入与输出 缺省参数 1、缺省参数的概念 2、缺省参数分类 1、全缺省参数 2、半缺省参数 函数重载 1、函数重… 目录 命名空间 1、命名空间的定义 2、命名空间的使用 1、加名空间名称和作用域限定符 2、使用using namespace 命名空间引入 3、使用using将命名空间中某个成员引入 C的输入与输出 缺省参数 1、缺省参数的概念 2、缺省参数分类 1、全缺省参数 2、半缺省参数 函数重载 1、函数重载的概念 2、c支持函数重载的原理 引用 1、引用概念 2、引用的特性 3、常引用 4、引用的使用场景 1、做参数 2、做返回值 5、传值传引用效率比较 1、传参比较 2、做为返回值比较 6、引用和指针的区别 1、语法概念 2、底层实现 3、汇编层面对比 4、引用和指针的不同点 内联函数 1、概念 2、特性 auto关键字 1、auto简介 2、auto的使用细则 3、auto不能推导的场景 基于范围的for循环(C11) 1、范围for的语法 2、范围for的使用条件 指针空值nullptr(C11) 1、C98中的指针空值 2、C11中的nullptr 命名空间 在C/C中变量函数以及类都是大量存在的。存在的这些类、变量、函数的名称都将存在全局作用域中。倘若函数、变量、类的名称相同的时候会产生命名冲突 例如 #include stdio.h #include string.hint strstr 20;int main() {int strstr 10;return 0; }//error错误strstr重定义 //因为在string.h文件中包含一个同名的strstr函数 // 而头文件被包含之后strstr函数也就存在与全局域了 //所以我们再定义一个rand变量的时候会产生一个命名冲突的问题 为了规避命名冲突的问题C中提出了namespase也就是定义命名空间域来解决 1、命名空间的定义 定义 定义命名空间需要用到namespace关键字namespace后面跟命名空间的名字该名字是我们自己取的随后下面对接一个{}大括号{}大括号中的就是命名空间中的成员命名空间的成员可以是变量、常量、函数、结构、也可以另一个命名空间 代码 //C库里面的文件C的头文件STL库……等都是存放在std命名空间域中的 #include iostream//用namespase 关键字定义命名空间 //NanShe 是命名空间名是我们自己起的 namespace NanShe {//命名空间的成员//可以是常量、变量、函数、也可以是命名空间//常量 #define N 10//变量int a 19;//函数int add(int a, int b){return a b;}//也可以另一个命名空间(嵌套命名空间)namespace N1{int a 29;//变量const float b 3.14;//常变量//函数int sum(double a, double b){return a b;}}}int main() {return 0; } 注意1 同一个工程中允许存在多个同名的命名空间。而编译器最后在处理的时候会将多个同名的命名空间最后会合并成一个命名空间切记同名的命名空间中不可再出现相同的变量或函数名……等若出现相同则合并之后会发生命名冲突问题 代码 //在同一个工程中 //若多个命名空间域的相域名相同 //编译器在处理的时候会进行合并 //合并后若两个命名空间的成员有名称相同的 //会出现命名冲突报错重定义 namespace NanShe {int b 20;//变量const int d 23;//常变量//交换函数int Swap(int* left, int* right){int tmp *left;*left *right;*right tmp;} }namespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }int main() {return 0; } 总结注意 定义一个命名空间就定义了一个新的作用域命名空间中所有的内容都局限与该命名空间中 2、命名空间的使用 命名空间定义之后该如何使用命名空间的成员呢 错误的使用 namespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }int main() {//错误的使用方式不能直接进行访问使用printf(%d, c);return 0; }//error(报错):c未声明的标识符 //不可直接使用C因为编译器在搜索的时候默认先搜索main函数的局部区域 //再去搜索全局区域搜索完全局区域之后就结束搜获不会主动去命名空间中去搜索 //搜获顺序局部域-全局域-结束不会主动去命名空间域搜索 命名空间的使用有三种方式如下解释 1、加名空间名称和作用域限定符 命名空间名作用域限定符(::) 使用方法在我们要使用的成员前面加上命名空间名和作用域限定符通过指定命名空间名称以及作用域限定符号进行访问当指定命名空间后编译器会自动去我们所指定的命名空间里面寻找我们所使用的成员若成员存在则正常访问不存在则报错 代码 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }int main() {//通过指定命名空间进行访问命名空间名作用域限定符)printf(c %d\n, NanShe::c);//指定访问NanShe命名空间中的成员 cint ret NanShe::add(10, 25);//指定访问命名空减间中的add函数printf(Add(10,25) %d\n, ret);//printf(%d\n, NanShe::b);//访问空间中不存在的成员 error报错:未声明的标识符return 0; } 注意 作用域限定符前面不指定任何命名空间名的时候默认访问的是全局域若不加作用域限定符默认访问的是局部域 代码 #include iostream//全局 int a 20;int main() {int a 10;printf(%d\n, a);//不加作用域限定符默认去局部域搜索printf(%d\n, ::a);//加作用域限定符前面不指定命名空间默认搜索全局域return 0; } 2、使用using namespace 命名空间引入 using namespace 命名空间名 展开命名空间域就是将该命名空间的内容都进行展开暴露在全局域中当命名空间全部展开之后我们就可以对该命名空间的成员进行访问 代码 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }//展开整个命名空间域将该空间暴露在全局域中 using namespace NanShe;int main() {//命名空间全部展开之后可直接进行访问成员printf(%d\n, c);printf(%d\n, add(10, 30));return 0; } 注意 整个命名空间展开暴露在全局之后有很大的风险。一旦全局域中存在与该命名空间中的成员命名相同的成员时。直接使用的时候会发生一个错误错误内容时不明确该使用那个此时必须指定命名空间访问才能进行正常访问 代码 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }//展开整个命名空间域将该空间暴露在全局域中 using namespace NanShe;int c 222;int main() {//展开之后是由风险的若全局域中存在同名的使用不明确printf(%d\n, c);return 0; } //error(报错C的使用不明确不知道要使用那个域的内容 解决方案 展开全局之后我们依然可以通过指定命名空间来进行访问 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }//展开整个命名空间域将该空间暴露在全局域中 using namespace NanShe;int c 222;int main() {int c 20;//展开之后全局域中存在与其成员同名的时候我们进行指定命名空间访问printf(NanShe c %d\n, NanShe::c);//指定访问NanShe命名空间域中的Cprintf(全局 c %d\n, ::c);//指定访问全局域中的Cprintf(局部 c %d\n, c);//默认访问局部域中的C//进行访问NanShe空间域的C 并且修改它的值NanShe::c 100;printf(修改后的NanShe c %d\n, NanShe::c);//修改NanShe命名空间域中的C 是不影响局部域和全局域中的c的printf(\n修改NanShe命名空间域中的 C 不影响局部域和全局域的C\n);printf(全局 c %d\n, ::c);printf(局部 c %d\n, c);return 0; } 总结 展开命名空间域在全局命名相同的请况下展开是非常不建议的需要择情况而定谨慎展开操作 有一个问题 那我们展开之后又进行指定访问展开整个命名空间域有啥作用呢是不是多次一举了。那么我们此时可以考虑使用下面一种方法进行展开也就是选择性展开命名空间里面的成员我们需要那个展开那个大大方便了我们的操作 3、使用using将命名空间中某个成员引入 用using展开命名空间中的指定成员 用using 命名空间名::成员 进行指定展开成员操作。有些情况下为了防止命名空间中的其它成员和全局域中的成员同名发生不确定错误。我们进行指定展开我们所需要访问的成员即可 代码 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }//进行指定展开NanShe命名空间域中的add成员 using NanShe::add;int main() {//直接进行访问addprintf(%d\n, add(12,45));return 0; } 注意 指定展开的成员也要注意是否和全局域中的命名相同若有相同的定然不能指定展开。也不可进行指定访问。然会出现重定义错误 代码 #include iostreamnamespace NanShe {int c 30;//加法函数int add(int a, int b){int z a b;return z;} }//进行指定展开NanShe命名空间域中的c成员 using NanShe::c;//全局 int c 22;int main() {//直接进行访问c,出现重定义错误printf(%d\n, c);//指定命名空间NanShe访问也出现重定义错误printf(%d\n, NanShe::c);//指定全局域访问也出现重定义错误printf(%d\n,::c);return 0; } //error(错误c重定义多次初始化 总结 在部分展开的时候一定要明确全局中是否有同名的若有不展开进行指定访问操作。若没有可进行展开访问操作 C的输入与输出 在C中有两个流分别代表输入和输出 1、cout标准输出对象控制台cin标准输入对象键盘、在使用两者的前提下都必须包含iostream头文件C的头文件是包含在std命名空间域中的要使用输入和输出得按照命名空间的使用方式使用std。输入cin  输出cout 2、cout和cin是全局流对象endl是特殊的C符号表示换行输出它们都包含在iostream头文件中 3、 是流插入运算符、是流提取运算符 4、C的输入输出会自动识别类型以及格式。比起C语言更加方便不需要像printf/scanf输入输出时那样需要控制格式 代码 //包含头文件 #include iostream//展开std命名空间域 using namespace std;int main() {int a 0;int b 0;int c 0;//cin标准输入对象输入a的值会自动识别类型cin a;//cout标准输出对象输出a自动识别类型输出,endl表示换行cout a endl;//输入b和c的值cin b c;//输出b和ccout b c;return 0; } 注意 C中为了和C的头文件区分也为了正确的使用命名空间域C规定头文件不带.h旧编译器VC6.0中还支持iostream.h的写法后续编译器已经不在使用该.h的写法了后续C我们也推荐写ioseamstd这样的写法 缺省参数 1、缺省参数的概念 概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用的时候如果没有指定实参则采用该形参的缺省值否则使用指定的实参 代码 #include iostream//指定展开 using std::cout; using std::cin; using std::endl;//定义函数给参数,缺省值 int add(int a 20 , int b 10) {return a b; }int main() {//若不指定参数会使用缺省值来计算int ret add();//输出cout ret endl;//若指定参数会将实参当成值ret add(1, 2);cout ret endl;return 0; } 注意 函数的参数给缺省值的时候如果有函数的声明建议在声明处给缺省值。若没有声明情况下才在函数定义上给缺省值。如果声明和定义同时都在缺省值要么给声明要么给定义不能同时给缺省值建议有声明的情况下缺省值给声明没有声明的情况下给定义。若两者同时存在给声明和定义都行但建议给声明不可同时给缺省值 代码 #include iostream//全部展开 using namespace std;//只有定义的请情况下缺省值给定义 // 即有有定义又有声明的情况下要么给声明缺省值要么给定义缺省值不能同时给 // 建议给声明缺省值 ////函数声明,声明处给参数 void add(int a 10, int b 20);//函数定义 void add(int a , int b) {cout a b endl; }int main() {//调用函数不传参add();//调用函数传参add(2, 1);return 0; } 2、缺省参数分类 1、全缺省参数 全缺省参数 顾名思义就是给函数的所有参数都给一个缺省值 代码 #include iostreamusing namespace std;//全缺省参数给所有参数都给一个参数值 void Sub(double a 3.12, double b 4.15, int c 10) {cout c - a - b endl; }int main() {//若不传参数则默认用缺省值计算Sub();//传参数用实参的参数计算Sub(1.1, 2.2, 12);return 0; } 2、半缺省参数 半缺省参数 就是只给部分参数缺省值剩余的参数不给缺省值但是有一点要注意在给部分参数缺省值的时候必须从右往左依次来给参数不能间隔给 代码 #include iostream//全部展开 using namespace std;//使用半缺省参数的函数从右往左依次给参数,不能间隔着给缺省值 void Add(int a, int b, int c 20) {cout a b c endl; } int main() {//没有给缺省值的参数必须传实参//有缺省值的参数不传参数默认使用它的缺省值Add(10,30);return 0; } 注意 1、半缺省值必须从右往左依次来给不能间隔的给 2、缺省参数不能在函数声明和定义同时出现 3、缺省值必须是常量或全局变量 代码 #include iostream//指定展开 using std::cin; using std::cout; using std::endl;//声明和定义不能同时出现参数//函数声明 void Sub(int a, int b, int c, int d);//缺省参数必须是常量或全局变量 #define N 100 int s 22; //参数的缺省值必须从右往左给不能间隔给 void Sub(int a, int b N, int c 10,int d s) {cout b - c -d - a endl; }int main() {Sub(15);return 0; } 函数重载 1、函数重载的概念 在自然语言中一个词可以有多种含义人们可以根据情景以及上下文来判断该词具体表示的含义。即该词被重载了 概念 函数重载是函数的一种特殊情况C允许在同名作用域中声明几个功能类似的同名函数而这些同名函数的形参参数个数或类型或类型的顺序不同。常用来处理不同数据类型实现同一功能的问题 通俗点讲就是在同一作用域中可出现同一名称的函数但要求是同名函数的类型或者参数个数或类型顺序不相同至少要满足其中一种才能实现重载的概念 1、参数类型不同 #include iostreamusing namespace std;//1、参数类型不同 void Add(int a, int b) {int c a b;cout c endl; }void Add(double a, double b) {double c a b;cout c endl; }int main() {Add(1, 3);Add(1.2, 3.14);return 0; } 2、参数个数不同 #include iostreamusing namespace std;//2、参数个数不同 void fun(int a) {cout a endl; }void fun(int a, int b) {cout a b endl; }int main() {fun(10);fun(10, 20);return 0; } 3、参数类型顺序不同 #include iostreamusing namespace std;//3、参数类型顺序不同 //注意同类型的参数顺序不同是不能构成重载的 void Sub(int a, float b) {cout (b - a) endl; }void Sub(float b, int a) {cout (b - a) endl; }int main() {Sub(10, 12.3f);Sub(3.14f, 1);return 0; } 注意 1、参数类型顺序不同是不同类型的参数的顺序不同才能构成重载同类型参数顺序不同是不能构成重载的 2、函数的返回值不同是不构成函数重载的 3、构成函数重载的函数也是可以给缺省值的 2、c支持函数重载的原理 我们知道C语言是不支持函数重载的而C是支持函数重载的为什么 我们知道在C/C中一个程序要运行起来需要经历几个阶段预处理、编译、汇编、链接。源文件先进行编译生成目标文件再将所有目标文件和链接库进行链接最后生成一个可执行程序详解参考主页程序环境和预处理(C语言文章 我们知道在链接街阶段当一个源文件中调用另一个源文件中的函数的时候链接器会找函数的地址找到之后链接到一起在C中我们知道链接过程中链接器是通过函数的名称去寻找其所对应的函数。而每个编译器都有自己的函数名修饰规则 由于Windows下的vs对链接时产生的函数名修饰规则比较复杂而Linux的g修饰规则简单易懂、所以我们使用Linux来查看函数名的修饰 使用C语言编译器编译后的结果 结论 在Linux下 采用和gcc编译完成后函数名的修饰没有发生改变 采用C编译器编译后的结果 注意 用g编译的时候函数名的修饰是发生改变的由图add函数为例_z3Addii)我们可推断_z是一个前缀3表示函数名的长度紧接着是Add表示函数名第一个i表示int类型第二个i也表示int类型。由此可知在C中函数名修饰的时候是添加了参数类型以及函数名长度等信息进行修饰 由此修饰规则我们可知 当函数名相同的时候参数类型不同以及参数个数不同和参数类型的顺序不同编译器在底层对函数名进行修饰的时候最终结果也是不同的因为结果不同在链接阶段找到的函数也是不同的会根据不同的函数名修饰结果找到不同的函数 总结 综上所述C语言是没办法支持函数重载的因为同名函数没办法区分。而在C中可出现参数类型不同、或者参数个数不同、或者参数类型顺序不同的同名函数也就是构成函数重载而返回值不同是不构成函数重载的因为返回值是不参与函数名修饰规则的 总代码 #include iostreamusing namespace std;//1.参数类型不同,构成函数重载 void Add(int a, int b) {cout a b endl; } void Add(float a, float b) {cout a b endl; }//2、参数个数不同构成函数重载 void Sub(int a, int b) {cout a - b endl; } void Sub(int a, int b, int c) {cout a - b - c endl; }//3、参数类型顺序不同构成函数重载 void Mult(int a, float b) {cout a * b endl; } void Mult(float a, int b) {cout a * b endl; }//4、返回值不同是不构成函数重载的 //error(报错:无法重载仅按返回类型区分的函数 void Div(int a, int b) {cout a / b endl; }int Div(int a, int b) {return a / b; }int main() {//1、参数类型不同Add(1, 2);Add(1.1f, 2.2f);//2、参数个数不同Sub(9, 3);Sub(10, 1, 2);//3、参数类型顺序不同Mult(2, 2.5);Mult(1.25, 5);//4、返回值不同是不构成重载的Div(3, 5);int ret Div(3, 5);//error:无法重载仅按返回类型区分的函数return 0; } 引用 1、引用概念 概念 引用不是新定义了一个变量而是对已存在的变量取了一个别名编译器不会对单独给引用开辟空间它和它引用的变量共用一块内存空间。 例如 一个人可以有很多个名字比如博主名字叫楠舍有人叫博主小楠也有人叫博主小舍也有人叫博主舍舍……等很多名字而除了楠舍本名之外其它的都是博主的别名归根结底这些名字都是在指一个人只是叫法不同而已而在编程中起别名就被叫做引用 语法 类型 引用变量名(引用对象名 引用实体 代码 #include iostream using namespace std;int main() {//定义变量a并赋值int a 10;//给a起别名bb是a的引用b和a是表示同一块空间int b a;cout a endl;cout b endl;return 0; } 2、引用的特性 特性 1、引用在定义时必须初始化 2、一个变量可以有多个引用 3、引用一旦引用一个实体再不能引用其它实体 4、引用与实体的类型必须相同 1、引用在定义时必须初始化 #include iostreamusing namespace std;int main() {int a 20;//定义a的引用b引用在定义的时候必须初始化int b a;//不初始化会报错int c;//error(报错引用变量C需要初始值设定项return 0; } 2、一个变量可以有多个引用 #include iostreamusing std::cout; using std::endl;int main() {int a 20;//一个变量可以有多个引用int b a;int c a;//也可以通过引用再取引用int d b;cout a endl;cout b endl;cout c endl;cout d endl;return 0; } 3、引用一旦引用一个实体就不能引用其它实体 #include iostreamusing std::cout; using std::endl;int main() {int a 30;int c 40;//b引用实体aint b a;//一旦引用一个实体不能再引用其它实体b c;//此操作不是引用而是赋值操作是将c空间的值赋值给b引用的空间acout a 的地址 a endl;cout b 的地址 b endl;cout c 的地址 c endl endl;cout a 的值 a endl;cout b 的值 b endl;cout c 的值 c endl;return 0; } 4、引用与实体的类型必须相同 #include iostreamusing namespace std;int main() {int a 10;//引用与实体的类型必须相同int b a;//引用与实体类型不同会进行报错double c a;//error报错):E0434 无法用int类型的值初始化double 类型的引用(非常量限定)return 0; } 3、常引用 概念 引用在引用一个实体的时候权限可以平移可以缩小但权限不能放大 例如 用const修饰的变量的值是不能被改变的而如果用一个不用const修饰的引用去引用该变量是不允许的因为不用const修饰的引用的权限是可以改变其值而该变量本身的权限是不能改变值。即权限进行了放大是不被允许的 #include iostreamusing namespace std;int main() {//引用的时候权限可以平移可以缩小但是不可以放大//引用中权限可以平移const int a 20;const int c a;//引用中权限可以缩小double fd 3125;const double fg fd;//const修饰的常变量const int s 10;//对赋予常变量的属性进行引用是不可行的int b s;//因为b引用将a的权限放大了本身a是由const修饰的是不可改变的// 而a的引用b不是由const修饰的所以b引用的权限是可以改变的// 引用b对a本身的权限进行了放大所以是不允许的return 0; } 4、引用的使用场景 1、做参数 引用做参数 用引用做参数可以直接通过形参访问实参不再使用繁琐的指针来传地址解引用访问更加方便了我们的使用 代码 #include iostreamusing namespace std;//交换函数指针写法 void Swap(int* a, int* b) {int tmp *a;*a *b;*b tmp; }//交换函数引用写法 void Swap(int a, int b) {int tmp a;a b;b tmp; }int main() {int a 10;int b 20;Swap(a, b);cout a b endl;Swap(a, b);cout a b endl;return 0; }//引用更加方便我们操作我们可以直接操作 //指针法中如果是n级指针就很吃力了 //而如果是引用我们直接引用就能直接访问到它了 总结 引用大大方便了我们的操作如果是n级指针我们再进行解引用访问就很繁琐而且还容易出错。而使用引用我们就可以直接访问到要访问的内容了使用起来更加方便 2、做返回值 引用做返回值 引用是可以做函数返回值的函数在返回值的时候会开辟一个临时变量将返回的值存储起来随后销毁函数栈帧再将临时变量里的值返回到调用地方去而引用做返回值是不开辟临时空间的是直接返回 代码 #include iostreamusing namespace std;//用引用做返回值 int Sub() {static int a 10;return a; }//用引用做返回值 int Add(int a, int b) {int c a b;return c;//返回c空间的引用在返回的时候不开辟临时变量 }int main() {int sun Sub();//用sun接收a的引用sun就是a的引用// 而a变量是存储在静态区的Sub栈帧销毁a不会销毁// 自始至终都可以通过sun访问到acout sun endl;int ret Add(1, 3);//用ret接收c的引用//ret就是c空间的引用//有风险如果Add函数的栈帧被操作系统清理了或者被其它函数使用了//ret会产生随机值的风险cout ret endl;//调用以下Sub函数Sub();//此时的ret会成为一个不可预测的结果//因为Sub函数调用的时候会复用Add函数使用的栈帧cout ret endl;return 0; } 注意 如果函数返回时出了函数作用域如果返回对象的空间没有销毁没有还给操作系统则可以使用引用返回。若空间销毁还给了操作系统则必须使用传值返回继续使用引用会出现不可预测的结果 5、传值传引用效率比较 1、传参比较 传值传引用效率 以值作为参数或者返回类型在传参和返回期间函数不会直接传递实参或者将变量直接返回而是传递实参或者返回变量的一份临时拷贝。因此用值作为参数或者返回值类型效率是非常底下的尤其是当参数或者返回类型非常大时效率就更底然而引用的效率就比较高了引用只是取别名不需要将类型全都传过来也不需要进行临时拷贝 例如 传入或者返回一个非常大的结构体时 传值调用的时候形参是实参的临时拷贝会拷贝一份非常大的结构体返回的时候也是一样会产生零时变量来保存这个非常大的结构体此时耗费的空间就很大效率也很底下 传引用只是对其空间起了个别名可以直接通过别名访问该空间一般理解下引用是不占用空间的实际上引用的底层和指针一样的哪怕占用空间也占用几个字节相对于传值调用引用的效率就非常之高了 代码 #include iostreamusing namespace std;//定义学生结构体 struct student {char name[10];char id[12];int age;double hight;double wight; };//传值调用,形参是实参的一份临时拷贝改变形参不影响实参 void Print(struct student s) {cout s.id endl;cout s.name endl;cout s.age endl;cout s.hight endl;cout s.wight endl; }//引用是给sd空间起了个别名s通过别名访问空间效率高 void Print(struct student s,int a) //a只是为了实现函数重载而传的不必太在乎 {cout s.id endl;cout s.name endl;cout s.age endl;cout s.hight endl;cout s.wight endl;cout a endl; } int main() {struct student sd { 0 };//传值调用Print(sd);//引用Print(sd,10);return 0; } 效率比较代码 #include iostream using namespace std;#include time.h struct A { int a[10000]; };void TestFunc1(A a) {}void TestFunc2(A a) {}void TestRefAndValue() {A a;// 以值作为函数参数size_t begin1 clock();for (size_t i 0; i 10000; i)TestFunc1(a);size_t end1 clock();// 以引用作为函数参数size_t begin2 clock();for (size_t i 0; i 10000; i)TestFunc2(a);size_t end2 clock();// 分别计算两个函数运行结束后的时间cout TestFunc1(A)-time: end1 - begin1 endl;cout TestFunc2(A)-time: end2 - begin2 endl; }int main() {//效率测试TestRefAndValue();return 0; }//引用的效率明显比传值的效率高数据越大效率越明显 总结 传引用的效率比传值的效率高的多数据越大越明显 2、做为返回值比较 值和引用作为返回值性能比较 值作为返回值返回时会产生一个临时变量拷贝一份该值放入到临时变量中再通过零时变量进行返回。当数据量过大的时候相应的临时变量的空间也会开很大性能就比较底下而使用引用返回时是不需要开辟临时空间的引用是直接返回别名不需要用临时空间效率相对就快一点 性能比较代码 #include iostream using namespace std; #include time.h struct A { int a[10000]; }; A a;// 值返回 A TestFunc1() { return a; }// 引用返回 A TestFunc2() { return a; }void TestReturnByRefOrValue() {// 以值作为函数的返回值类型size_t begin1 clock();for (size_t i 0; i 100000; i)TestFunc1();size_t end1 clock();// 以引用作为函数的返回值类型size_t begin2 clock();for (size_t i 0; i 100000; i)TestFunc2();size_t end2 clock();// 计算两个函数运算完成之后的时间cout TestFunc1 time: end1 - begin1 endl;cout TestFunc2 time: end2 - begin2 endl; }int main() {TestReturnByRefOrValue();return 0; }//引用的性能比传值的性能明显高的多的多 总结 传值和传引用在作为返回类型上性能有很大的差距引用比传值更优 6、引用和指针的区别 1、语法概念 语法概念 在语法概念上引用就是一个别名没有独立的空间和其引用的实体共用同一片空间。 代码 #include iostreamusing namespace std;int main() {//语法概念上引用是不开空间和实体共用一块空间int a 10;//b是a的引用int b a;//引用和实体共用同一块空间cout a endl;cout b endl;return 0; } 2、底层实现 底层实现 引用在底层实现上实际上是开辟空间的因为引用时按照指针的方式来实现的 代码 #include iostreamusing namespace std;int main() {//底层实现中引用是开空间的//底层指针和引用的实现方式是一样的int a 10;int b a;b 20;int* pa a;*pa 20;cout a endl;return 0; } 3、汇编层面对比 汇编层面对比 汇编底层引用和指针实现是一样的  4、引用和指针的不同点 不同点 1、引用概念上定义一个变量的别名指针存储一个变量的地址 2、引用在定义时必须初始化指针没有要求 3、引用在初始化时引用一个实体后就不能再引用其它实体。指针可以改变指向 4、没有NULL引用。但有NULL指针 5、sizeof中结果不同引用的结果是引用类型的大小。指针始终是4/8个字节32位下4字节64位下8字节 6、引用进行自增或自减即引用实体自增或自减。指针自增或自减指针向前或向后偏移一个类型大小 7、有多级指针没有多级引用 8、访问实体不同指针需要解引用。引用编译器自己处理 9、引用比指针使用起来相对更加安全指针可能有NULL指针野指针不安全 内联函数 1、概念 概念 以inline修饰的函数叫做内联函数在编译的时候C编译器会在调用内联函数的地方进行展开。展开之后没有函数调用时建立栈帧的开销内联函数提升程序的运行效率 理解 未用lnline修饰的函数在汇编层面会出现栈帧调用指令Call指令 若在上述函数前增加inline关键字将其改成内联函数在编译期间编译器会用函数体替换函数调用 Vs下查看 1、在release模式下直接查看汇编代码中是否有call Add 函数调用指令 2、在Debug模式下需要对编译器进行设置才能查看否则内联函数是不会展开的因为展开了不便于我们调试因为在Debug模式下编译器默认对代码不进行优化  用inline修饰后 适用 代码短小而调用次数少的函数适合用inline修饰成为内联函数。内联函数的特性是在调用位置展开减少函数栈帧的开销若是代码太庞大展开之后也会占用部分空间。再倘若调用次数过多每次都在调用的地方展开也是一种空间的消耗倒不如开辟栈帧的效率了实际上编译器也会对上面的情况自动进行处理编译器允许短小的函数用inline 修饰。不允许将庞大的用inline修饰若你执意用inline修饰了编译器底层是不会把该函数当成内联函数的会按照正常的函数开辟栈帧空间处理当然每个编译器规定允许成为内联函数的代码行数是不一样的在VS2019下是10行以内允许以外不允许 2、特性 特性 1、inline是一种以空间换时间的做法如果编译器将函数当成内联函数在编译阶段编译器会用函数体替换函数调用也就是展开。缺陷可能使目标文件变大。优点少了栈帧开销提高程序运行效率 2、inline对于编译器来说只是一种建议不同编译器对inline的处理是不一样的。建议将函数规模较小的、且不是递归、不频繁调用的函数用inline修饰而inline对编译器只是建议具体是否采纳你的建议就要看编译器本身的处理了很多编译器都不支持内联递归函数而且代码太长太多的函数编译器也不会采用inline的建议总的来说inline只是一种建议也就是对编译器发出的请求而编译器可以忽略这个请求 3、inline不建议函数声明和定义分离分离之后会导致链接错误。因为在编译的时候inline函数就被在调用地方展开了而在链接阶段就找不到地址了无法链接就会报错 代码 // Fun.h 代码 #pragma once #include iostream using namespace std;//声明 inline int Add(int left, int right);//Fun.cpp 代码 #include Fun.h//定义 inline int Add(int left, int right) {return left right; }//Test.cpp 代码 #include Fun.hint main() {int ret Add(1, 2);cout ret endl;return 0; }//error(报错链接错误无法解析的外部符号 auto关键字 1、auto简介 简介 在早期C/C中auto的含义是使用auto修饰的变量是具有自动存储器的局部变量但很少有人去用它 在C11中标准委员会赋予了auto全新的含义auto不再是一个存储类型指示符而是一个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期推导而得 通俗点说auto关键字就是用来自动识别类型的关键字 代码 #include iostream using namespace std;int main() {int a 10;auto b a;auto c c;auto d abcd;//打印类型cout typeid(a).name() endl;cout typeid(b).name() endl;cout typeid(c).name() endl;cout typeid(d).name() endl;auto e;//无法编译通过auto定义的变量必须给它初始化//auto使用来识别类型的而不初始化压根就不知道是什么类型return 0; } 注意 auto修饰的变量必须进行初始化在编译阶段编译器是根据初始化的表达式来推导auto的类型。auto并非是一种类型的声明而是一种类型的占位符编译器在编译时会将auto替换成变量实际的类型 2、auto的使用细则 1、auto与指针和引用结合起来使用 用auto声明指针类型时用auto和auto* 没有任何区别但在声明引用类型时必须加上 代码 #include iostream using namespace std;int main() {int a 10;//声明指针类型auto b a;auto* c a;//声明引用类型auto d a;//打印类型cout typeid(a).name() endl;cout typeid(b).name() endl;cout typeid(c).name() endl;cout typeid(d).name() endl;*b 20;cout a endl;*c 30;cout a endl;d 40;cout a endl;return 0; } 2、在同一行定义多个变量 用auto 在用一行声明多个变量时这些变量必须是相同类型的变量因为编译器在编译阶段实际只对第一个变量类型进行推导然后用推导出来的类型来定义后面的其它变量 代码 #include iostreamusing namespace std;int main() {//推导定义多个变量时这些变量必须时同类型的//因为编译器只推导第一个变量的类型后面的由推导出来的类型来定义auto a 10, b 20, c 30;cout a endl;cout b endl;cout c endl;auto d 12, e 3.14;//这种情况会报错//error(报错在声明符列表中“auto”必须始终推导为同一类型return 0; } 3、auto不能推导的场景 1、auto不能作为函数的参数 auto作为形参类型的时候会报错因为编译器无法进行对形参实际类型进行推导 代码 #include iostreamusing namespace std;//auto不能作为函数参数 //因为编译器无法对实际的参数类型进行推导 void Add(auto a) {a;cout a endl; }int main() {Add(10);return 0; }//error(报错参数不能为包含“auto”的类型 2、auto不能直接用来声明数组 C11规定 auto不能用来推导数组的类型 代码 #include iostreamusing namespace std;int main() {//auto不能推导数组的类型auto a[] { 1,2,3,4,5 };auto b[] { 1.2,1.3,1.4 };return 0; }//error(报错“auto[]”: 数组不能具有其中包含“auto”的元素类型 //“auto”类型不能出现在顶级数组类型中 总结 为了避免与C98混淆C11只保留了auto作为类型指示符的用法 auto在实际中的用法主要是范围for,以及lambada表达式等进行配合使用 基于范围的for循环(C11) 1、范围for的语法 语法 若用c98遍历一个数组需要先计算个数再用for循环遍历 代码 #include iostreamusing namespace std;int main() {int arr[] { 1,2,3,4,5,6,7,8,9 };//改变数组元素的值for (int i 0; i sizeof(arr) / sizeof(arr[0]); i){arr[i] * 10;}//遍历数组for (int i 0; i sizeof(arr) / sizeof(arr[0]); i){cout arr[i] ;} }然而对于一个有范围的数组集合而言对于我们来说再去写循环的范围是多余的有时候还会犯错误。因此C11中引入了基于范围的for循环。for循环的括号里面分为两部分第一部分是范围内用于迭代的变量第二部分则表示被迭代的范围两者之间用冒号分割开 代码 #include iostreamusing namespace std;int main() {//遍历数组int arr[] { 1,2,3,4,5,6,7,8,9 };//范围for遍历数组,用auto关键字来识别类型,且通过引用改变它的值//第一部分是auto e 表示迭代的变量,是对数组每个元素的引用//第二部分arr 表示迭代的范围是arr数组内for (auto e : arr){e * 10;}//范围for遍历数组,用auto关键字来识别类型\//第一部分是auto e 表示迭代的变量//第二部分arr 表示迭代的范围是arr数组内for (auto e : arr){cout e ;} } 注意 范围for与普通循环类似可用continue 结束本次循环也可用break跳出循环 2、范围for的使用条件 1、for循环迭代的范围必须是确定的 对于数组而言就是数组元素的第一个元素和最后一个元素的范围。对于类而言应该提供begin和end的方法begin和end就是for循环迭代的范围 代码 #include iostream using namespace std;//这种情况下 for的范围就不确定了不能使用 //因为arr是一个指针没法确定去确定数组的范围会报错 void Print(int arr[]) {for (auto e : arr){cout e ;} }int main() {int arr[] { 1,2,3,4,5,6,7,8,9 };Print(arr);return 0; }//error(报错):此基于范围的“for”语句需要适合的 begin 函数但未找到 2、迭代的对象要实现或操作。 关于该使用我们后续迭代器文章再进行详解 指针空值nullptr(C11) 1、C98中的指针空值 在C98中指针的空值为NULL而NULL的底层是一个宏在传统的C头文件stddef.h中可以看到 由以上可知NULL可能被定义为字面常量或者被定义为无类型指针void的常量。不论采取哪种定义使用NULL空值的指针时会出现一些问题  例如以下函数调用问题 #include iostream using namespace std;void f(int) {cout f(int) endl; } void f(int*) {cout f(int*) endl; } int main() {//程序本意是第一个调用int参数的函数ff(0);//第二个NULL调用int*参数的函数实际上NULL也是调用第一个int参数的函数f(NULL);//只有通过强制类型转换之后才可调用int*的函数f((int*)NULL);return 0; } 以上代码程序本意是想通过调用int类型参数的函数f通过NULL 调用int*类型参数的函数f。然而在实际上我们在调用的时候是两者都调用了int类型参数的函数f。因为NULL在底层宏定义的时候可能会被定义成0在C98 中字面常量0 既可以是一个整型数字也可以是无类型的指针void*)常量但编译器默认情况下会将其看成是一个整数常量来处理。所以才会出现该问题则必须进行强制转换之后才可达到效果 2、C11中的nullptr nullptr: 为了解决以上C98中的问题C11中以关键字的形式引入了nullptr关键字。nullptr更加明确的表示是空指针后续我们在给指针初始值的时候建议采用nullptr。nullptr是指针特有的使用nullptr就很好的解决和规避使用NULL导致出现的问题在C11中sizeof(nullptr)和sizeof((void*)0) 所占字节数相同 代码 #include iostream using namespace std;void f(int) {cout f(int) endl; } void f(int*) {cout f(int*) endl; } int main() {//对于这种情况我们使用nullptr 就很好的解决问题了f(0);//调用int参数类型的函数ff(nullptr);//调用 int* 参数类型的函数 f//sizeof(nullptr)和sizeof((void*)0)占用字节数相同//三者所占大小相同cout sizeof(nullptr) endl;cout sizeof((void*)0) endl;cout sizeof(NULL) endl;return 0; } 注意 1、在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C11作为新关键字引入的。 2、在C11中sizoef(nullptr) 和sizeof((void*)0)所占字节数相同 3、为了提高代码效率建议使用nullptr
http://www.w-s-a.com/news/824964/

相关文章:

  • 什么是网站建设外包html 门户网站
  • 资阳市建设局网站微信开发公司
  • wap建站程序源码可不可以异地建设网站
  • 优秀企业网站的特点网站标签名词
  • 建材网站建设案例淄博网站建设培训
  • 纯代码添加wordpress网站底部导航宝塔自助建站源码
  • 网站设计技术有哪些?青岛网站建设工作室
  • 网站怎样建设才叫人性化宣传
  • 济南网站制作方案做淘客网站备案
  • h5企业网站只做做php门户网站那个系统好
  • 长春阿凡达网站建设建网站如果不买域名别人能不能访问
  • 佛山网站建设策划东莞建设工程交易网
  • 制作公众号网站开发濮阳建网站
  • 屏南网站建设兼职旅游网站建设方案两百字
  • 最牛的网站建设网站建设的规模设想
  • 马云之前做的网站企业形象策划
  • ie9网站后台编辑器代发qq群发广告推广
  • 百度怎样建立一个网站嘉兴高端网站定制
  • 国外设计网站怎么进入电子网站建设前台设计
  • 中方建设局网站济南网站建设公司电子商务网站
  • 如何做网站编辑 沒技术济南企业做网站推广网站
  • 网站模板 百科北京中高风险地区最新名单最新
  • 高校网站建设前言做公众号的公司是什么公司
  • 网站备案怎么登陆短视频培训学校
  • 百度图片点击变网站是怎么做的北京市建设工程质量监督站网站
  • 在线建站模板重庆网站建设大概需要多少钱
  • 建设网站公司电话号码wordpress 即时通讯
  • 网站设计用的技术拓者吧室内设计网app
  • 河北seo优化_网络建设营销_网站推广服务 - 河北邢台seo网站建设运行情况报告
  • 建设银行内部网站6画册设计是什么