• 头文件区别
  • 标准i/o库区别
  • 命名空间的创建
    • 命名空间的好处
  • 命名空间的访问
    • 不嵌套访问
    • 嵌套访问
    • 用using namespace实现简单嵌套访问
  • using namespace 作用域问题
  • ::(作用域分辨符的作用)
  • “using ::函数名”的作用
  • using 替换typedef的功能
  • 函数重载
    • 参数数量不同
    • 参数类型不同
    • 参数顺序不同
  • 函数参数中const小知识
  • 函数缺省
  • 新数据类型
    • bool类型的大小
    • 左值引用
    • auto和decltype的用法

头文件区别

  • c++标准库中所有的头文件包含方式采取无.h后缀的方式包含如:#include
  • 在c++文件中包含c标准库的头文件有两种方式
    • 有后缀.h
      • 如: #include,#include
    • 无后缀
      • 如:#include,#include
  • 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;};

可以看见在名空间内部实现函数和结构体的方式有两种

  1. 直接将函数和结构体定义在命名空间内部
  2. 先在命名空间内部声明再在外部定义

命名空间的好处

  1. 可以提高标识符的使用率(翻译过来就是可以使用相同的变量名)
  2. 避免命名污染

命名空间的访问

不嵌套访问
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(11.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*既可以传字符串常量,又可以传字符串变量

函数缺省

注意:

  1. 在写多文件时只能在头文件中写函数的缺省,不能在实现时写函数缺省
  2. 在写单文件时可以在函数实现时写函数缺省
  3. 在写函数缺省的时候只能依次从右向左缺省

让我们来看看写单文件时的函数缺省写法

#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;}