- 头文件区别
- 标准i/o库区别
- 命名空间的创建
- 命名空间的好处
- 命名空间的访问
- 不嵌套访问
- 嵌套访问
- 用using namespace实现简单嵌套访问
- using namespace 作用域问题
- ::(作用域分辨符的作用)
- “using ::函数名”的作用
- using 替换typedef的功能
- 函数重载
- 参数数量不同
- 参数类型不同
- 参数顺序不同
- 函数参数中const小知识
- 函数缺省
- 新数据类型
- bool类型的大小
- 左值引用
- auto和decltype的用法
头文件区别
- c++标准库中所有的头文件包含方式采取无.h后缀的方式包含如:#include
- 在c++文件中包含c标准库的头文件有两种方式
- 有后缀.h
- 如: #include,#include
- 无后缀
- 如:#include,#include
- 有后缀.h
- c++和c的头文件扩展名不同(这里的头文件指自己写的头文件)
- c的扩展名是.h
- c++的扩展名是.hpp
注意:c++兼容c语言所以在c++文件中,自己写的头文件可以是.h为后缀,也可以是.hpp为后缀
标准库i/o区别
- C输入输出需要包含#include,C++输入输出需要包含#include
命名空间的创建
namespace MM{ int age;void print(){printf("我在MM里面\n");}struct Info{ char*name; int num;};}
这是第一种写法,可以将函数和结构体定义在命名空间内部
让我们来看看第二种写法
namespace GG{int age;//声明函数void print();//声明结构体struct Info;}//在命名空间外实现void GG::print(){printf("我在GG外面实现的\n");}struct GG::Info{ char*name; int num;};
可以看见在名空间内部实现函数和结构体的方式有两种
- 直接将函数和结构体定义在命名空间内部
- 先在命名空间内部声明再在外部定义
命名空间的好处
- 可以提高标识符的使用率(翻译过来就是可以使用相同的变量名)
- 避免命名污染
命名空间的访问
不嵌套访问
namespace MM{ int age;void print(){printf("我在MM里面\n");}struct Info{ char*name; int num;};}int main(){MM::age=1;MM::print()MM::Info a={"张三",3}; //注意在C++中结构体定义变量用结构体名也可以struct MM::Info b={"李四",4};//加上struct 定义变量也可以return 0;}
嵌套访问
namespace A{int a;namespace B{int b;namespace C{int c;}}}int main(){//访问A里面的aA::a;//访问A里面的B里面的bA::B::b;//访问A里面的B里面的C里面的cA::B::C::c;return 0;}
用using namespace实现简单嵌套访问
#includenamespace A{int a=1;namespace B{int b=2;namespace C{int c=3;}}}int main(){//去掉前缀访问A里面的ausing namespace A;printf("a=%d\n",a);//去掉前缀访问A里面的B里面的busing namespace A::B;printf("b=%d\n",b);//去掉前缀访问A里面的B里面的C里面的cusing namespace A::B::C;printf("c=%d\n",c);//访问a,b,cprintf("a=%d,b=%d,c=%d\n",a,b,c);return 0;}
输出结果a=1b=2c=3a=1,b=2,c=3
using namespace 作用域问题
#includeusing namespace Q{int a=1;int b=2;}void test_usingnamespace(){using namespace Q;printf("a=%d\n",a);printf("a=%d\n",b);}int main(){test_usingnamespace();//此时我在这里去掉前缀访问a=2;//注意这是错误的写法,因为此时using namespace Q 的作用域管不到这里,只在test_usingnamespace()函数中起作用//此时正确写法应该是如下Q::a=2;printf("a=%d\n",Q::a); return 0;}
输出结果a=1b=2a=3
::(作用域分辨符的作用)
#includeint a=3;int main(){int a=1;printf("a=%d\n",a); //当全局变量和局部变量同名时根据就近原则,取a=1printf("a=%d\n",::a); //如果在a前面加上::(作用域分辨符)则取全局变量a=3;return 0;}
输出结果a=1a=3
注意::: (作用域分辨符)只在C++中有效C源文件中没有,这个是C++针对这种情况做出的优化
“using ::函数名”的作用
#include//第一种写法void printData(){printf("%d\n", 3);}namespace G{void printData(){//函数根据就近原则调用,此时形成死递归printData();}}int main(){G::printData();return 0;}
编译结果warning C4717: “G::printData”: 如递归所有控件路径,函数将导致运行时堆栈溢出
//第二种写法void printData(){printf("%d\n", 3);}namespace G{void printData(){using::printData;//声明下面函数的来源于全局,下面函数将调用全局函数printData();}}int main(){G::printData();return 0;}
输出结果3
using 替换typedef的功能
int main(){typedef int INT;//将int取别名为INTINT a=1;//这里其实是 int a=1;sing INT=int; //这里也是取别名,将int 取别名为INTINT b=2; //这里其实是 int b=2;return 0;}
这个sing 取别名标识符=被取别名标识符,是C++里面的功能,与typedef 被取别名标识符 取别名标识符 有着相同的功能,如果非要我来评价一下哪个更好理解,我觉得C++的应该更好理解,如sing INT = int 可以理解为int 类型赋值给INT,让INT拥有int 类型。
函数重载
参数数量不同
#includevoid test(int a,int b){printf("我有两个参数\n");}void test(int a){ printf("我只有一个参数\n");}int main(){test(1);test(1,2);return 0;}
输出结果我只有一个参数我有两个参数
参数类型不同
void test(int a){printf("我是整型\n");}void test(double a){ printf("我是双精度浮点型\n");}int main(){test(1);test(1.2);return 0;}
参数顺序不同
错误展示×
#includevoid test(int a,int b){printf("我们顺序不同\n");}void test(int b,int a){ printf("我们顺序不同\n");}int main(){test(1);test(1,2);return 0;}
注意:上面这种写法是错误的,程序不会去看你的形参,而是去看你的参数的类型,我们不看形参,只看类型,可以看出来这两个函数是一模一样的,不满足函数重载的条件,像test(int a,int b)
参数类型一样则不满足参数顺序交换的条件,函数参数类型不同时,才满足参数顺序交换
正确展示√
#includevoid test(int a,double b){printf("我们两个函数参数类型顺序不同,且函数中两个参数类型不同\n");}void test(double b,int a){ printf("我们两个函数参数类型顺序不同,且函数中两个参数类型不同\n");}int main(){test(1,1.1);test(1.1,2);return 0;}
函数参数中const小知识
#includevoid test_const(char*str) //此时参数没加const修饰,让我们看看效果吧{printf("在C++中在传字符串时是比较严格的\n");}int main(){test_const("我进来啦")return 0;}
让我们来看看编译结果吧
编译结果error C2664: “void test_const(char *)”: 无法将参数 1 从“const char [9]”转换为“char *”
很明显编译都无法通过,那么接下来让我们来看看能否传字符串变量进去
#includevoid test_const(char*str) //此时参数没加const修饰,让我们看看效果吧{printf("在C++中在传字符串时是比较严格的\n");}int main(){char arr[]="我来试试";test_const(arr);return 0;}
输出结果在C++中在传字符串时是比较严格的
从上面的输出结果可以看出函数参数在没有用cosnt 来修饰的时候是可以传字符串变量的,那么怎么才能既可以传字符串常量,又可以传字符串变量呢?接下来让我们来看看const 修饰char*的作用吧!!!
测试一、现在传的是字符串常量
#includevoid test_const(const char*str) {printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");}int main(){test_const("我进来啦") //此时是字符串常量return 0;}
输出的结果加了const修饰char*既可以传字符串常量,又可以传字符串变量
测试二、现在传的是字符串变量
#includevoid test_const(const char*str) {printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");}int main(){char arr[]="我来试试";test_const(arr);return 0;}
输出的结果加了const修饰char*既可以传字符串常量,又可以传字符串变量
函数缺省
注意:
- 在写多文件时只能在头文件中写函数的缺省,不能在实现时写函数缺省
- 在写单文件时可以在函数实现时写函数缺省
- 在写函数缺省的时候只能依次从右向左缺省
让我们来看看写单文件时的函数缺省写法
#includevoid test(int a=1,int b=2,int c=3){printf("a=%d,b=%d,c=%d\n",a,b,c);}int main(){test(100);test(100,200);test(100,200,300);return 0;}
输出结果a=100,b=2,c=3a=100,b=200,c=3a=100,b=200,c=300
让我们来看看注意点3的错误写法
#includevoid test(int a=1,int b,int c=3){printf("a=%d,b=%d,c=%d\n",a,b,c);}int main(){test(100);return 0;}
如果跳跃式缺省,在函数调用时,此时我传入了100,这100,程序不知道应该分配给谁了,它不会自动帮你分配给第二个参数b,这样缺省是不对的
新数据类型
bool类型的大小
#includeusing namespace std;int main(){bool flag=true;cout<<"字节大小:"<<sizeof(flag)<<"\n";return 0;}
输出结果字节大小:1
左值引用
什么是左值引用呢?顾名思义就是等号左边的标识符称为左值,左值引用的表示方法为:类型& 标识符=左值,就是给一段相同的内存取一个别名,可能大家现在还是一头雾水,接下来我们一起看看左值引用是如何应用的吧,请看代码
第一种用法:
#includeusing namespace std;int main(){int a=3;int& b=a; //这一条语句的意思是给a取了一个别名为bb=30;//改变b就是改变a,因为b就是a ,它们是共用的同一段内存cout<<"a="<<a<<"\n";cout<<"b="<<b<<"\n";return 0;}
输出结果a=30b=30
第二种用法
#includeusing namespace std;void test1(int*p){*p=30;}void test2(int&b){b=300; }int main(){int a=3;/*test1和test2都是为了改变外部变量a的值,只是方式各不同,test1是通过传地址改变a的值,test2是通过左值引用的方法改变a的值无须传地址*/test1(&a);cout<<"a="<<a<<"\n"; test2(a);cout<<"a="<<a<<"\n"; return 0;}
test1输出的结果a=30test2输出的结果a=300
auto和decltype的用法
auto和decltype两者搭配使用,auto用来推断类型,decltype可以使用auto推断出的类型创建变量,话不多说,我们来看代码
#includeusing namespace std;int main(){auto b = 3;//此时auto 将b推断成int类型decltype(b) w = 10;/* decltype(b)->int w=10; decltype()可以拿着auto推断出来的类型 创建相应类型的变量 */cout << w;return 0;}