渭南市网站建设,企业年金辞职了就白交了吗,长链接转化成短链接工具,选择一个网站进行优化目录
前言#xff1a;
命名空间
命名空间的定义
命名空间的使用
c输入与输出
缺省参数
函数重载
引用
引用的特性
常引用
引用的使用场景
引用做参数
引用做返回值
引用与指针的区别
内联函数
内联函数的特性 前言#xff1a; C 语言是结构化和模块化的语言
命名空间
命名空间的定义
命名空间的使用
c输入与输出
缺省参数
函数重载
引用
引用的特性
常引用
引用的使用场景
引用做参数
引用做返回值
引用与指针的区别
内联函数
内联函数的特性 前言 C 语言是结构化和模块化的语言适合处理较小规模的程序对于复杂的问题规模较大 程序需要高度的抽象和建模时 C 语言则不合适为了解决软件危机 20 世纪 80 年代 计算机界提出了 OOP(object oriented programming面向对象)思想 支持面向对象的程序设计语言 应运而生 1982 年 Bjarne Stroustrup博士 在 C 语言的基础上引入并扩充了面向对象的概念发明了一 种新的程序语言。为了表达该语言与 C 语言的渊源关系命名为 C 因此 C是基于C语言而产生的它既可以进行C语言的过程化程序设计又可以进行以抽象数据类型为特点的基于对象的程序设计还可以进行面向对象的程序设计 命名空间 由于变量 函数 类的名称存在于全局作用域中会导致命名冲突 使用命名空间的目的是对标识符的名称进行本地化以防止命名冲突或名字污染 # include stdio.h
# include stdlib.h //stdlib.h文件中包含库函数rand()函数
int rand 20; //全局变量rand与stdlib.h文件中的库函数rand()发生命名冲突
int main()
{printf(%d\n, rand);return 0;
}
//代码运行结果 error C2365:rand:重定义,以前定义是函数 命名冲突的场景 1. 程序员定义的变量与库函数名相冲突 2. 多人协作同一个大型项目程序员之间发生函数名命名冲突 命名空间的定义 程序设计者根据需要指定一些带有名字的空间域将一些全局实体分别存放于各个命名空间中从而与其他全局实体分割出来 定义命名空间的关键字namespace 语法 namespce 命名空间名 { 命名空间成员 } //命名空间名为Qspace
namespace Qspace
{//定义变量int a 10;//定义函数int Add(int x, int y){return x y;}//定义类型struct ListNode{int val;struct ListNode* next;};
}命名空间嵌套定义
namespace Addspace
{int Add(int x, int y){return x y;}//嵌套定义命名空间Subspacenamespace Subspace{int sub(int x, int y){return x - y;}}
} 多个文件定义同名的命名空间编译器最终会合成同一个命名空间中
//test.h文件
# include iostream
namespace MSpace
{int Mul(int x, int y){return x*y;}
}//test.cpp文件
# include test.h
namespace MSpace
{int Add(int x, int y){return x y;}namespace Subspace{int sub(int x, int y){return x - y;}}
}
int main()
{int ret MSpace::Mul(2, 3);printf(%d\n, ret);return 0;
}
命名空间的使用
方式一加命名空间名称及作用域限定符(::) 即命名空间名 :: 命名空间成员名
namespace Qspace
{int a 10;int Add(int x, int y){return x y;}struct ListNode{int val;struct ListNode* next;};
}
int main()
{printf(%d\n, Qspace::a); //变量的访问方式int ret Qspace::Add(2, 3);//函数的访问方式printf(%d\n, ret);struct Qspace::ListNode node { 0, NULL };//结构体类型的访问方式return 0;
}
方式二使用using将命名空间中某个成员引入 即using 命名空间名 :: 命名空间成员名
namespace MSpace
{int a 10;int b 20;
}
//using 命名空间名::命名空间成员名
using MSpace::a;int main()
{printf(%d , a);return 0;
}
方式三 使用using namespace 命名空间名引入即using namespace 命名空间名 using namespace 命名空间名 将整个命名空间展开使得特定命名空间所有成员名可见此时使用命名空间下的变量、函数不需要加作用域限定符使得隔离失效 namespace Addspace
{int a 10;int Add(int x, int y){return x y;}
}
using namespace Addspace;
int main()
{scanf(%d, a);int ret Add(2, 3);printf(%d\n, ret);return 0;
}
c输入与输出 std是C标准库的命名空间cout为iostream所定义的标准输出对象(控制台)终端cin为iostream所定义的标准输入对象(键盘)因此使用cout , cin必须包含 iostream 头文件及按命名空间使用方法使用stdendl(endline)表示换行输出相当于换行符包含在iostream头文件中 流插入运算符与cout配合使用可以将输出的变量或者字符串流入到cout中cout负责输出到终端 流提取运算符与cin配合使用将用户输入的值流入到某变量中cin以遇到空格键tab键或者换行符作为分隔符停止读取 # include iostream
using namespace std;
int main()
{cout hello world! endl;return 0;
}运行结果 //cin遇到空格键 Tab键 Enter键停止读取
# include iostream
using namespace std;
int main()
{char a[10] { 0 };cin a;cout a endl;return 0;
}
运行结果 注cout与cin可以自动识别变量类型 缺省参数 缺省参数是声明或定义函数时为函数的形式参数指定一个默认值缺省值 调用该函数时如果没有指定实参则采用形参的缺省值否则使用指定的实参 # include iostream
using namespace std;
void Fun(int a 10)
{cout a endl;
}
int main()
{Fun(); //没有传参时,使用形式参数的默认值Fun(20); //传参时,使用指定的实参return 0;
} 运行结果 缺省参数的分类 全缺省参数函数定义或声明时为该函数所有形式参数指定缺省值 半缺省参数函数定义或声明时为该函数的部分形式参数指定缺省值但是缺省值只能从右向左给值必须连续给值 # include iostream
using namespace std;
void Fun(int a 10,int b20,int c30)//全缺省参数
{cout a a ;cout b b ;cout c c endl;
}
int main()
{Fun();Fun(1);Fun(1, 2);Fun(1, 2, 3);return 0;
} 运行结果 # include iostream
using namespace std;
void Fun(int a,int b20,int c30)//半缺省参数
{cout a a ;cout b b ;cout c c endl;
}注缺省参数不能在函数声明和定义同时出现若声明与定义皆具有缺省参数恰巧两个位置提供的值不同此时编译器无法确定到底该采用那个缺省值当声明与定义分离时只能在函数声明处给出缺省参数 函数重载 函数重载C允许在同一作用域中声明几个功能类似的同名函数但是要求同名函数的 形参列表(参数个数 或 参数类型 或 类型顺序)不同返回值无要求 //参数类型不同
int Add(int a, int b)
{return ab;
}
double Add(double a, double b)
{return ab;
}
//参数个数不同
int Fun(int a);
int Fun(int a,int b);
//形参类型的顺序不同
int Sub(int a, char b);
int Sub(char b, int a);为什么C支持函数重载而C语言不支持函数重载呢 程序运行时需要经历如下阶段预处理 编译 汇编 链接而在链接阶段会生成符号表建立函数名与地址一一映射的关系C语言链接函数地址时采用函数名寻找函数定义而对于同名函数无法区分函数地址但是C是通过函数修饰规则如Linux下g 修饰规则 _Z 函数名字符个数函数名参数首字母来区分修饰后名字不同自然支持了重载 引用 引用不是新定义一个变量而是 给已存在变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量 共用同一块内存空间 语法 类型 引用变量名(对象名) 引用实体 //原变量与引用变量共用同一块内存空间
int main()
{int a 10;int pa a;printf(%p\n, a);printf(%p\n, pa);return 0;
} 运行结果 注引用类型与引用实体必须是相同类型 引用的特性
引用在定义时必须初始化
int main()
{//正确示例int a 10;int pa a;//错误示例int b 20;int pc;//编译时出错return 0;
}
一个变量既可以有多个引用又可以给引用变量继续取引用
int main()
{int a 10;int pa a;int pb a;int pc pa;cout a a endl;cout pa pa endl;cout pb pb endl;cout pc pc endl;return 0;
}
运行结果 引用一旦引用一个实体不能引用其他实体 int main()
{int a 10;int pa a;int d 1;// pa变成d的别名还是d赋值给papa d;//pa的引用实体为a,让引用变量pa引用dcout a endl;return 0;
}
运行结果 将d的值赋值给pa又因为pa是a的引用所以a的值间接变成了1 常引用
int main()
{const int a 10;int b a;//错误做法const int b a;//正确做法return 0;
} 变量a由于const修饰具有常属性不可被修改而引用变量b与原变量应具有相同属性不能被修改但是引用变量放大了权限导致编译错误 int main()
{//权限可以缩小int c 20;const int d c;const int e 10;return 0;
} 变量c的属性为可读写引用变量d的属性为可读权限缩小并不会导致编译错误 int main()
{int i 10;double j i;//整型提升double rj i;//错误做法const double rm i;//正确做法return 0;
} 当发生整型提升时系统不是直接将其赋值给另外一个变量的而是会创建一个常量区来存放变量提升后的结果此时变量具有了常属性一旦出现权限的放大必然导致编译错误 总结类型转换整型提升 截断产生临时变量临时变量具有常属性 引用的使用场景
引用做参数 C语言阶段函数通过传址调用实现通过形参修改实参由于形参与实参数值上相同空间上独立所以实参是形参的临时拷贝而引用变量在语法上与原变量共用同一块内存空间若形参采用引用变量的方式也可达到修改实参 //指针方式
void Swap1(int* pa, int* pb)
{int tmp *pa;*pa *pb;*pb tmp;
}
//引用方式
void Swap2(int a, int b)
{int tmp a;a b;b tmp;
}
引用做返回值 void Func()
{int c 0;cout c endl;
}
int main()
{Func();//Func()函数第一次调用结束,销毁第一次为func()函数所开辟的函数栈帧Func();return 0;
}
运行结果 由于空间可以重复利用第一次调用Func()函数并为其开辟函数栈帧并在函数栈帧中为变量c分配空间当函数运行结束后该函数所对应的栈空间由操作系统回收但数据是否被清理是不确定的当第二次调用Func()函数时仍然在该地址处创建了c这个变量 int Add(int a, int b)
{int c a b;return c;
}
int main()
{int ret Add(1, 2);Add(3, 4);cout Add(1,2) ret endl;return 0;
}
运行结果 ret其实指向的是c那块空间的地址当c发生了变化ret也就会随之发生改变 int Add(int a, int b)
{static int c a b;return c;
}
int main()
{int ret1 Add(1, 2);cout Add(1,2) ret1 endl;int ret2 Add(3, 4);cout Add(3,4) ret2 endl;return 0;
}
运行结果 当Add()函数运行结束后由于static修饰的局部变量存放于静态区出函数作用域并不会被销毁此时可以引用返回但是第二次调用Add()函数发生错误原因为静态成员变量只会被初始化一次 总结引用做返回值时返回的数据必须由static修饰或者是存放于堆区的数据或者是全局变量等不会随着函数调用的结束而被销毁的数据 引用与指针的区别 1. 引用概念上定义一个变量的别名指针存储一个变量地址 2. 引用在定义时必须初始化指针没有要求 3. 引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何一个同类型实体 4. 没有NULL引用但有NULL指针 5. 在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32位平台下占4个字节) 6. 引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小 7. 有多级指针但是没有多级引用 8. 访问实体方式不同指针需要显式解引用引用编译器自己处理 9. 引用比指针使用起来相对更安全 内联函数 宏是一种在程序中定义的简单代码替换机制它们通常用于定义常量或执行重复性操作与函数不同宏是在编译时展开的而不是在运行时调用 宏的声明方式 #define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表它们可能出现在stuff中
//宏函数
# define Add(x,y) ((x)(y))
int main()
{int a 10;int b 20;int ret Add(10, 20);cout ret ret endl;return 0;
} 宏的缺点 1、容易出错语法细节多 2、不能调试预编译阶段进行了替换 3、没有类型安全的检查 由于宏的缺点从而产生内联函数替代宏函数 内联函数以关键字inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销内联函数提升程序运行的效率 inline int Add(int x, int y)
{return x y;
}
int main()
{int a 10;int b 20;int ret Add(10, 20);cout ret ret endl;return 0;
}
内联函数的特性 inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小(即函数不是很长具体没有准确的说法取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性inline不建议声明和定义分离分离会导致链接错误。因为inline被展开就没有函数地址了链接就会找不到由于内联函数所生成的地址不会进入符号表也就没有函数名与地址一一映射的关系所以发生链接性错误