- 头文件区别
- 标准i/o库区别
- 命名空间的创建
- 命名空间的访问
- using namespace 作用域问题
- ::(作用域分辨符的作用)
- "using ::函数名"的作用
- using 替换typedef的功能
- 函数重载
- 函数参数中const小知识
- 函数缺省
- 新数据类型
头文件区别
- c++标准库中所有的头文件包含方式采取无.h后缀的方式包含如:#include< iostream >
- 在c++文件中包含c标准库的头文件有两种方式
- 有后缀.h
- 如: #include< stdio.h >,#include< stdlib.h >
- 无后缀
- 如:#include< cstdio >,#include< cstdlib >
- 有后缀.h
- c++和c的头文件扩展名不同(这里的头文件指自己写的头文件)
- c的扩展名是.h
- c++的扩展名是.hpp
注意:c++兼容c语言所以在c++文件中,自己写的头文件可以是.h为后缀,也可以是.hpp为后缀
标准库i/o区别
- C输入输出需要包含#include< stdio.h >,C++输入输出需要包含#include< iostream >
命名空间的创建
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里面的a
A::a;
//访问A里面的B里面的b
A::B::b;
//访问A里面的B里面的C里面的c
A::B::C::c;
return 0;
}
用using namespace实现简单嵌套访问
#include<stdio.h>
namespace A
{
int a=1;
namespace B
{
int b=2;
namespace C
{
int c=3;
}
}
}
int main()
{
//去掉前缀访问A里面的a
using namespace A;
printf("a=%d\n",a);
//去掉前缀访问A里面的B里面的b
using namespace A::B;
printf("b=%d\n",b);
//去掉前缀访问A里面的B里面的C里面的c
using namespace A::B::C;
printf("c=%d\n",c);
//访问a,b,c
printf("a=%d,b=%d,c=%d\n",a,b,c);
return 0;
}
输出结果
a=1
b=2
c=3
a=1,b=2,c=3
using namespace 作用域问题
#include<stdio.h>
using 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=1
b=2
a=2
::(作用域分辨符的作用)
#include<stdio.h>
int a=3;
int main()
{
int a=1;
printf("a=%d\n",a); //当全局变量和局部变量同名时根据就近原则,取a=1
printf("a=%d\n",::a); //如果在a前面加上::(作用域分辨符)则取全局变量a=3;
return 0;
}
输出结果
a=1
a=3
注意::: (作用域分辨符)只在C++中有效C源文件中没有,这个是C++针对这种情况做出的优化
"using ::函数名"的作用
#include<stdio.h>
//第一种写法
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取别名为INT
INT a=1; //这里其实是 int a=1;
using INT=int; //这里也是取别名,将int 取别名为INT
INT b=2; //这里其实是 int b=2;
return 0;
}
这个using 取别名标识符=被取别名标识符,是C++里面的功能,与typedef 被取别名标识符 取别名标识符 有着相同的功能,如果非要我来评价一下哪个更好理解,我觉得C++的应该更好理解,如using INT = int 可以理解为int 类型赋值给INT,让INT拥有int 类型。
函数重载
参数数量不同
#include<stdio.h>
void 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;
}
参数顺序不同
错误展示×
#include<stdio.h>
void 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)
参数类型一样则不满足参数顺序交换的条件,函数参数类型不同时,才满足参数顺序交换
正确展示√
#include<stdio.h>
void 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小知识
#include<stdio.h>
void 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 *”
很明显编译都无法通过,那么接下来让我们来看看能否传字符串变量进去
#include<stdio.h>
void test_const(char*str) //此时参数没加const修饰,让我们看看效果吧
{
printf("在C++中在传字符串时是比较严格的\n");
}
int main()
{
char arr[]="我来试试";
test_const(arr);
return 0;
}
输出结果
在C++中在传字符串时是比较严格的
从上面的输出结果可以看出函数参数在没有用cosnt 来修饰的时候是可以传字符串变量的,那么怎么才能既可以传字符串常量,又可以传字符串变量呢?接下来让我们来看看const 修饰char*的作用吧!!!
测试一、现在传的是字符串常量
#include<stdio.h>
void test_const(const char*str)
{
printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");
}
int main()
{
test_const("我进来啦") //此时是字符串常量
return 0;
}
输出的结果
加了const修饰char*既可以传字符串常量,又可以传字符串变量
测试二、现在传的是字符串变量
#include<stdio.h>
void test_const(const char*str)
{
printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");
}
int main()
{
char arr[]="我来试试";
test_const(arr);
return 0;
}
输出的结果
加了const修饰char*既可以传字符串常量,又可以传字符串变量
函数缺省
注意:- 在写多文件时只能在头文件中写函数的缺省,不能在实现时写函数缺省
- 在写单文件时可以在函数实现时写函数缺省
- 在写函数缺省的时候只能依次从右向左缺省
让我们来看看写单文件时的函数缺省写法
#include<stdio.h>
void 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=3
a=100,b=200,c=3
a=100,b=200,c=300
让我们来看看注意点3的错误写法
#include<stdio.h>
void 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类型的大小
#include<iostream>
using namespace std;
int main()
{
bool flag=true;
cout<<"字节大小:"<<sizeof(flag)<<"\n";
return 0;
}
输出结果
字节大小:1
左值引用
什么是左值引用呢?顾名思义就是等号左边的标识符称为左值,左值引用的表示方法为:类型& 标识符=左值,就是给一段相同的内存取一个别名,可能大家现在还是一头雾水,接下来我们一起看看左值引用是如何应用的吧,请看代码
第一种用法:
#include<iostream>
using namespace std;
int main()
{
int a=3;
int& b=a; //这一条语句的意思是给a取了一个别名为b
b=30; //改变b就是改变a,因为b就是a ,它们是共用的同一段内存
cout<<"a="<<a<<"\n";
cout<<"b="<<b<<"\n";
return 0;
}
输出结果
a=30
b=30
第二种用法
#include<iostream>
using 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=30
test2输出的结果
a=300
auto和decltype的用法
auto和decltype两者搭配使用,auto用来推断类型,decltype可以使用auto推断出的类型创建变量,话不多说,我们来看代码
#include<iostream>
using 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;
}