ic电子网站建设,电商网站建设方案PPT,wordpress 交互插件,徐州人才网官方网站目录 
介绍#xff1a; 
一#xff0c;命名空间 
1-1#xff0c;命名空间的定义 
1-2#xff0c;命名空间的使用 
1-3#xff0c;C标准官方命名空间 
二#xff0c;缺省参数 
2.1#xff0c;缺省参数分类 
三#xff0c;函数重载 
四#xff0c;引用 
4-1#xff0c;…目录 
介绍 
一命名空间 
1-1命名空间的定义 
1-2命名空间的使用 
1-3C标准官方命名空间 
二缺省参数 
2.1缺省参数分类 
三函数重载 
四引用 
4-1引用的使用 
4-2常引用 
4-3引用的使用场景 
4-4引用的效率分析以及与指针的关系 
五内联函数 介绍 本文开始从C到C的过度C是C的进阶版在C中本身存在很多不足和不安全性C是进一步弥补了C的不足并提供了更高级的用法不仅如此大部分C编译器还支持C语言的用法但C语言不支持C的用法这样一来C即包括了C语言的优点还拥有了自己的独特优势在后面的写入中笔者会将两者语言掺和起来以方便学者们理解。在平常区分C语言和C我们可直接根据两者的后缀名C语言的基础文件都是以.c为后缀而C的基础文件都以.cpp为后缀。 
一命名空间 在C/C中变量、函数和以后我们要学习的类都是大量存在的但如果变量或函数名重复了又当会如何C语言本身是无法解决此问题一旦重复系统将报错而C将会使用命名空间解决此问题。在C中专门有命名空间关键字namespace #include stdio.h int rand  0; int main() {     //系统将会报错因为在C语言库文件中就已定义了rand函数不可再次进行定义     fprintf(stdout, rand: %d, rand);     return 0; } 1-1命名空间的定义 定义namespace 命名空间的名字然后下面接一堆{}即可{}中即为空间中的成员。 解析命名空间相当于定义了一个新的作用域该空间中的所有内容都局限于该空间中不被外面影响因此它完美的解决了名称相同的问题。当要使用此空间中的成员时需要用到域的作用限定符即::。使用方法命名空间名字::成员。要注意的是使用结构体成员时struct 命名空间的名字::结构体名称并且命名空间还可以嵌套使用。 #include stdio.h//str是命名空间的名字 namespace str {     //命名空间里可以是任意类型     int rand  0;     int Add(int a, int b) {         return a  b;     }     struct student {         int age;         int height;     };     //命名空间的嵌套使用     namespace bitee {         int a  6;     } } int main() {    //整型类型的运用其它类型同理     fprintf(stdout, rand  %d\n, str::rand);    //结构体类型的运用     struct str::student a1;     a1.age  2;     fprintf(stdout, 结构体的运用: %d\n, a1.age);    //函数的运用     fprintf(stdout, Add(1, 2)  %d\n, str::Add(1, 2));    //命名空间的嵌套使用     fprintf(stdout, 嵌套使用: %d\n, str::bitee::a);     return 0; } 注意在这里要说明的是C允许同一个工程中存在多个相同名称的命名空间编译器最后会合成同一个命名空间中但同一个文件下不允许存在相同名称的命名空间因为这样运用的话当两者同时定义相同的变量名时编译器将不知所措。例如一个工程中的test.h和test.cpp文件中都有namespace std运行时两个的std会被合成一个。 1-2命名空间的使用 命名空间的使用有三种方法其中以上运用域的限定符::只是其中最普通的一种。接下来我们观察以下两种。 1使用using将命名空间中某个成员引入 #include stdio.h//str是命名空间的名字 namespace str {    //命名空间里可以是任意类型     int rand  0;     int Add(int a, int b) {         return a  b;     }     struct student {         int age;         int height;     };     namespace bitee {         int a  6;     } } //使用using后系统直接默认使用这时不用域的限定符即可表示使用里面的数据 using str::rand; using str::bitee::a; int main() {     fprintf(stdout, %d %d\n, rand, a);     return 0; } 2使用using namespace 命名空间名称 将其全部引入 //将命名空间全部导入系统这时会默认使用str using namespace str; int main() {     fprintf(stdout, %d %d\n, rand, bitee::a);     return 0; } 1-3C标准官方命名空间 之前就说过C是C的进阶C高级功能的其中之一就体现在C有自己的官方命名空间stdC将标准库的定义实现都放到这个命名空间中而std的使用通常与C的里iostream标准库文件密不可分两者一般是配合使用。 
C常用标准函数 1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时必须包含 iostream 头文件 以及按命名空间使用方法使用std。 2. cout和cin是全局的流对象endl是特殊的C符号表示换行输出他们都包含在包含 iostream 头文件中。 3. 是流插入运算符是流提取运算符。 4. 使用C输入输出更方便不需要像C中printf/scanf输入输出时那样需要手动控制格式。 C的标准输入输出可以自动识别变量类型。 
注意关于cout和cin还有很多更复杂的用法比如控制浮点数输出精度控制整形输出进制格式等等。因为C兼容C语言的用法这些又用得不是很多我们这里就不展开学习了。后续如果有需要笔者会详细跟大家介绍。 //引用头文件 #include iostream//标准命名空间的定义 using namespace std; int main() {     int a  5;     float b  3.5;     char str[]  abcdf;     cout  a    a  endl  b    b  endl  str    str  endl;     return 0; } 二缺省参数 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时如果没有指定实参则采用该形参的缺省值否则使用指定的实参。 #include iostream using namespace std; void Fun(int a  5) {     cout  a    a  endl; } int main() {     Fun(); //a  5采用该函数的缺省值5     Fun(10);//a  10有了实参就用该实参的值10     return 0; } 2.1缺省参数分类 
1全缺省参数 全缺省参数是函数参数中全部指定缺省值如下 void Func(int a  10, int b  20, int c  30) {     cout  a  endl;     cout  b  endl;     cout  c  endl; } 2半缺省参数 半缺省参数是函数参数中部分指定缺省值但这里有两条注意事项1半缺省参数必须从右往左依次来给出不能间隔着给。2. 缺省参数不能在函数声明和定义中同时出现如下 //参数从右到左必须依次给出 void Func(int a, int b  20, int c  30) {     cout  a  endl;     cout  b  endl;     cout  c  endl; } //错误运用 void Func(int a  10, int b, int c  30) {     cout  a  endl;     cout  b  endl;     cout  c  endl; } //缺省参数的使用注意 #include iostream using namespace std;//函数定义和声明中不能同时给缺省值因为编译器无法确定用哪个缺省值 //缺省值最好在声明中指定因为我们运用函数一般都是先声明完之后在定义如果系统先查看声明里面没有缺省参数而定义中存在缺省参数将会报错 void fund(int a  5) {     cout  a  endl; } int main() {     void fund(int a);     fund();//将会报错因为运行到函数声明时里面没有缺省参数而定义中指定缺省参数     return 0; } 当出现缺省参数时函数传参也必须要从右到左依次给出如下 #include iostream using namespace std; void Func(int a  10, int b  20, int c  30) {     cout  a  endl;     cout  b  endl;     cout  c  endl; } int main() {     Func();//a  10,b  20,c  30     Func(2);//a  2,b  20,c  30     Func(1, 2);//a  1,b  2, c  30     Func(1, 2, 3);//a  1,b  2, c  3     Func(, 3, );//错误用法     return 0; } 三函数重载 函数重载是函数的一种特殊情况C允许在同一作用域中声明几个功能类似的同名函数这些同名函数的形参列表(参数个数或类型或类型顺序)不同常用来处理实现功能类似数据类型不同的问题。 函数重载的注意要点其实主要根据编译器的识别。当函数名相同时只要当我们运用重名函数时能够区分两者的不同即可通过。如当传参时参数的类型不同或个数不同或顺序不同。如下 
例一 #include iostream using namespace std; int Func(int a  10, int b  20, int c  30) {     return a  b  c; } int Func(int a  1, int b  2) {     return a  b; } int main() {     Func();//系统将报错因为此时两个重名函数都满足条件编译器无法区分用哪个     Func(2);//系统报错同理     Func(1, 2);//系统报错同理     Func(1, 2, 3);//参数数量不同可以区分正常运行     return 0; } 例二 #include iostream using namespace std; void Func(int a  10, int b  20, int c  30) {     cout  a  b  c  endl; } int Func(int a  1, int b  2, int c  3) {     return a  b; } int main() {     Func(1, 2, 3);//函数类型虽不同但当调用时两者仍都满足所以出错     return 0; } 四引用 
4-1引用的使用 在C中出现了与指针效果相同的引用概念引用与指针不同的是引用不是新定义一个变量而是给已存在的变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间即可通过引用来改变变量与指针一样。 
使用方法类型 引用变量名(对象名)  引用实体。 void TestRef() {             int a  10;         int b  a;//定义引用类型         //输出两者的地址一样即b的改变也会影响a的改变             printf(%p\n, a);          printf(%p\n, b); } 图解 其中引用的使用要有以下注意要点 1引用类型必须和引用实体是同种类型的指针可以不同。 例如int a  5;chr b  a;将会出错因为变量a的类型为int指向a的引用b的类型也必须为int。 2引用在定义时必须初始化。 例如int c;将会出错因为引用没有初始化 3一个变量可以有多个引用。 例如int a  5;int b  a;int c  a;也就是说一个变量可有多个别名当a、b、c其中一个改变时这些别名和a的值都会被改变。 4引用一旦引用一个实体再不能引用其他实体。 例如int a  7, b  6;int c  a;c  b;错误因为引用c已经指向了一个实体不能改变引用的指向但是类似于c  b,c  9等操作是赋值操作没有改变引用的指向是可以的。  4-2常引用 常引用通常是引用常量的也可引用变量。具体定义const 类型 引用变量名(对象名)  常量。 
解析说明 首先我们先要明白无论什么变量只要加上const关键字修饰后相当于将变量的权限缩小了即此时的变量成为了常量不可改变而常引用就是将引用的权限缩小即局限了引用的作用范围当常引用指向变量时是将别名的权限限制了但变量名本身还可以改变。之所以常引用可以指向变量是因为在规定中权限小的可以指向权限大的权限大的不可指向权限小的而变量的值可以改变常量的值不可改变因此变量的权限要比常量的权限大。之所以要如此规定是因为当大权限的引用一旦指向常量时引用改变时常量也要改变显示是错误的而使用const修饰后的引用本身其实就是别名当指向大权限变量时其实只是将别名限制跟变量本身权限无关。指针与此也是同理。 还有在平常我们变量赋值操作时如果会发生类型转换中间都会产生一个临时变量赋值的操作不是变量之间直接赋值是将这个临时变量赋值而这种临时变量具有常性也就是此时是将常量赋值。没有类型转换将不会发生此事情将直接赋值。如下图 void TestConstRef() {     const int a  10;     //int ra  a;// 该语句编译时会出错a为常量权限大的不可指向权限小的     const int ra  a;    //int b  10;// 该语句编译时会出错b为常量权限大的不可指向权限小的     const int b  10;     //权限小的指向权限大的    int c  5;     const int e  c;//别名权限缩小     cout  c    e  endl;//输出5     c  6;     cout  c    e  endl;//输出6     //产生临时变量的情况     double d  12.34;      //int rd  d; // 该语句编译时会出错类型不同系统将具有常属性的临时变量进行赋值     const int rd  d;//相当于const int rd  12rd  12。} 4-3引用的使用场景 引用的使用场景其实跟指针的使用场景一样唯一要注意的是引用作为函数返回值的情况。当引用作为函数的返回值时请注意不要返回局部变量的引用因为局部变量是存放在内存中的栈区中栈区的数据会随着函数栈帧的销毁而销毁一旦栈帧销毁了局部变量的值将会随机但是如果编译器没有及时销毁函数栈帧这时里面的数据还存在将不会出现错误。如下 #include iostream using namespace std; int ADD(int a, int b) {     int c  a  b;     return c; } int main() {     cout  ADD(2, 3):   ADD(2, 3)  endl;     cout  ADD(2, 3):   ADD(2, 3)  endl;     cout  ADD(2, 3):   ADD(2, 3)  endl;     return 0; } 运行图 可发现本人的编译器没有及时销毁函数栈帧即系统没有及时回收内存。但是有些编译器会及时回收内存即销毁函数栈帧所以要想返回局部变量的引用我们可用关键字static将其放入到静态区中存储静态区中的数据只会在整个程序结束后才回收内存不会随着函数栈帧的销毁而销毁。即如下 #include iostream using namespace std; int ADD(int a, int b) {     static int c  a  b;     return c; } int main() {     cout  ADD(2, 3):   ADD(2, 3)  endl;     cout  ADD(2, 3):   ADD(2, 3)  endl;     cout  ADD(2, 3):   ADD(2, 3)  endl;     return 0; }     分析 在计算机中当函数返回值时其实系统先将此值进行了保存将此数据临时拷贝到了寄存器中当返回时其实就是从寄存器中返回。所以在以上返回局部变量的引用时笔者调用了多次因为寄存器保留了此数据当我们第二次调用此数据就彻底清空了所以只调用一次是不能确定函数栈帧是否被及时回收。 大多数情况下我们运用引用作为函数的返回值时是为了修改数值在后面的学习中我们会深入运用在这里先了解下即可。 4-4引用的效率分析以及与指针的关系 
引用的本质 引用的本质在C内部实现是一个指针常量说白了引用其实是按照指针方式来实现的并且在语法概念上引用就是一个别名没有独立空间和其引用实体共用同一块空间。 
1变量引用的使用 int a  10; int p  a;//系统内部自动转换为int* const p  a;其中指针常量是指针的指向不可改也就说明了为什么引用不可更改的原因  p  20;//内部发现p是引用自动转化为*p  20; 2常引用的使用 const int p  10;//加上const修饰后系统内部将代码转换为int a  10;const int p  a; 引用跟指针和普通数值之间的效率比较 首先我们来分析以值作为参数或者返回值类型的情况在传参和返回期间函数不会直接传递实参或者将变量本身直接返回而是传递实参或者返回变量的一份临时的拷贝因此用值作为参数或者返回值类型效率是非常低下的尤其是当参数或者返回值类型非常大时效率就更低。当我们运用指针时指针可是要在内存中开辟空间在运算时指针在内存中要经过复杂转换和相关逻辑的连接这些复杂运算很容易产生错误而且可读性也差在传值和指针作为传参以及返回值类型上效率相差就很大。引用的使用可达到指针的相同效果虽然当函数调用时仍要给形参分配存储空间但是引用本身就不另开空间运算时也是跟引用指向的实体运算一样没有复杂的逻辑结构。综上所述引用无论在效率上还是安全性上都要比指针高。 引用虽然相对于指针比较安全和高效但引用本身也不是绝对安全如果一旦使用不当也将会产生危险性。 五内联函数 在讲解内联函数之前我们先回顾下C语言中的宏。宏的用法跟函数类似它比函数高效的是宏的使用不用建立函数栈帧但宏本身也存在很多问题我们先观察以下代码 #define ADD(x, y) x  y; //int a  ADD(1, 2) * 5;转换后a  1  2 * 5  11,不符合我们的要求 #define ADD(x, y) (x  y) //int a  ADD(1 | 2, 1  2); 转换后a  (1 | 2  1  2),不符合我们的要求 #define ADD(x, y) (x)  (y) //int a  ADD(1, 2) * 5;转换后a  1  2 * 5  11,不符合我们的要求 #define ADD(x, y) ((x)  (y)); //写法正确 不难发现宏的使用虽然在效率上比函数高但本身存在很多细节观念复杂的宏使用很容易掉坑所以宏有以下优缺点 优点 1.增强代码的复用性。 2.提高性能。 缺点 1.不方便调试宏。因为预编译阶段进行了替换也就是不能调试难以发现错误 2.宏导致代码可读性差可维护性差容易出错。 3.没有类型安全的检查 。 由于宏的这些原因C使用了以下两中方法进行改进 1使用常量定义换用const enum(即枚举) 2使用短小函数的内联函数 枚举在这里我们先不讨论我们先观察内联函数。C中用的关键字inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销从这方面可看出内联函数提升了程序运行的效率。 
解析 1inline其实是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段系统会用函数体替换函数调用这样一来可能就会使目标文件变大但少了调用开销提高了程序的整体运行效率。 2inline虽然几乎解决了宏的所有缺陷但是inline的使用使空间消耗太大了所以当函数规模较小时编译器才会决定使用内联函数当函数规模较大或运用了递归时编译器将直接忽略了这种请求即内部还是没有使用内联函数。笔者建议对于函数规模较小且频繁调用时采用inline修饰。  3不同编译器内联函数的实现机制可能有所不同具体还要根据编译器的内部功能而定。 4inline函数不支持声明和定义分离开因为编译器一旦将一个函数作为内联函数处理就会在调用位置展开即该函数是没有地址的也不能在其他源文件中调用故一般都是直接在源文件中定义内联函数的。总的来说就是inline不支持头文件的定义。 5可以在同一个项目的不同源文件定义函数名相同但实现功能不同的内联函数。 
举例如下 //内部规模小系统将展开 inline int Add(int x, int y) {     int c  x  y;     return c; } //内部规模较大系统不会展开 inline int Add(int x, int y) {     int c  x  y;     int c1  x  y;     int c2  x  y;     int c3  x  y;     int c4  x  y;     int c5  x  y;     int c6  x  y;     int c7  x  y;     int c8  x  y;     int c9  x  y * c8;     int c10  x  y;     int c11  x  y;     return c1  c10 - c9; } //运用了递归系统将不会展开 typedef struct Node {     int val;     struct Node* left;     struct Node* right; }Node; inline int Tree(Node* root) {     if (!root) {         return 0;     }     int leftsize  Tree(root-left);     int rightsize  Tree(root-right);     return leftsize  rightsize; } 内联函数的运用虽然具有局限性但是它的优点不可忽视在后期的运用也是很重要的。它可以调试运用效率高语法也简单更不用建立栈帧大大的提升了效率。 补充本文讲解很多细节其实是为后面打基础部分内容设计到了很多原理这不仅是为了后面的开发打基础还是为了后面的深入学习做铺垫所以一定要理解这些原理和理清这些思路否则后面的文章学习中将会感到很困惑。最后要说的是C的学习本身就有很大的难度开头其实还好后面越深入难度越大我们一定要有个好的心态并积极练习才能学好这门技术。