我们先分别感受一下用c和c++写的hello word
//c语言
#include
int main()
{
printf("hello world");
}
//c++
#include
using namespace std;
int main()
{
cout << "hello word" << endl;
return 0;
}
我们发现:头文件不一样了,并且在主函数前多了个:using namespace std;
并且输出的函数也不一样了
让我们来分析分析
为什么c++要有这个东西,而c语言没有?
因为c语言出的比较早,它是有一些坑的
比如:
以下这个程序用c语言的逻辑来看没有任何问题 但是,它会出问题
#include
#include
int rand = 0;
int main()
{
printf("%d",rand);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aau9Caeo-1689596957592)(c++001.assets/image-20230717071846326.png)]
它说rand
重定义了,但是我们会很奇怪,我们只定义了一个rand
呀 ,这是为啥?
因为我们调用的头文件#include
中碰巧包含了一个叫rand
的函数,你又在程序中定义了一个全局变量也叫rand
所以就重命名了,那出现这种情况的时候我们该怎么办呢,(有些时候我们也不能不用这个stdlib.h
头文件,因为里面不只包含了rand
函数,也包含了一些我们会用到的其他的函数)那这个时候咋办?
为了解决这个问题,c++的创始人想出来了命名空间---namespace
这种方法
#include
#include
//命名空间
namespace wo_shuai
{
int rand = 0;
}
int main()
{
//访问全局的那个rand
printf("%p\n", rand);
//访问命名空间的那个rand
printf("%d\n", wo_shuai::rand);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fc4xKYK6-1689596957593)(c++001.assets/image-20230717082241250.png)]
wo_shuai::
中的::
叫域作用限定符
命名空间可以定义:
namespace wo_shuai
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
//命名空间里定义函数
int Add(int left, int right)
{
return left + right;
}
// 命名空间里定义结构体
struct Node
{
struct Node* next;
int val;
};
//命名空间里定义命名空间: 套娃
namespace xxx
{
int rand = 1; //还定义了相同的变量
}
}
// 定义的函数,全局的
int Add(int left, int right)
{
return (left + right) * 10;
}
int main()
{
printf("%d\n", wo_shuai::rand);
printf("%d\n", wo_shuai::Add(1,2));
printf("%d\n", Add(1, 2));
struct wo_shuai::Node node; //注意访问命名空间里的结构体的方法;
return 0;
}
但是,如果我们每次访问命名空间里的变量或函数都要指定一下,比如:wo_shuai::rand
会感觉很麻烦,
所以在变量名不冲突的情况下我们可以在开头展开命名空间,像这样:using namespace wo_shuai;
这样的话,如果要使用命名空间里的变量就可以直接使用了,但是这样的话,命名空间就有点 名存实亡 的感觉了
举个列子就相当于:命名空间就相当于一个景区,平常只有交了门票的才让进,但是展开命名空间的话就相当于直接把景区的围墙拆了,所有人都可以进去。
#include
#include
using namespace wo_shuai; //展开命名空间,如果把命名空间看作一个付费景区的话,展开命名空间就相当于拆掉景区围墙
namespace wo_shuai
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
//命名空间里定义函数
int Add(int left, int right)
{
return left + right;
}
// 命名空间里定义结构体
struct Node
{
struct Node* next;
int val;
};
//命名空间里定义命名空间: 套娃
namespace xxx
{
int rand = 1; //还定义了相同的变量
}
}
int main()
{
printf("%d\n", rand); //由于你把命名空间展开了,所以rand肯定会与stdlib.h中的rand冲突的,所以这个程序是会报错的
printf("%d\n", Add(1, 2));
printf("%d\n", Add(1, 2));
struct Node node; //由于展开了命名空间了,就直接访问命名空间里的结构体了
return 0;
}
既然将命名空间完全展开是有风险的我们可不可将命名空间部分展开呢?
答案是可以的
#include
#include
//定义一个命名空间
namespace wo_shuai
{
int rand = 10;
int size = 20;
}
//将命名空间部分展开
using wo_shuai::rand; //这种方式就展开了命名空间里的:rand
int main()
{
printf("%d\n", rand);
return 0;
}
当然如果部分展开也重名的话,那就别部分展开了
这个时候我们就可以来解释:using namespace std
这句代码的意思了
这句话的意思就是把:std这个名字的命名空间全部释放了。
那std是啥?
std是c++标准库的命名空间
#include
//全部展开
using namespace std;
int main()
{
cout << "我真帅呀" << endl;
return 0;
}
如果不用using namespace std; 不展开命名空间的话,编译器就找不到cout这个函数了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ctHk7Qkc-1689596957593)(c++001.assets/image-20230717103700376.png)]
但是我上面学了命名空间,我们可以这样
#include
//部分展开
using std::cout;
using std::endl;
int main()
{
cout << "我真帅呀" << endl;
return 0;
}
还可以这样
#include
int main()
{
//一个一个的展开
std::cout << "我真帅呀" << std::endl;
return 0;
}
还有一件事 命名空间可以自动的合并
#include
namespace shuai //命名空间你可以取一模一样的名字,它们会自动合并的,就比如这里的2个shuai;第一个shuai的a,b,第二个shuai的
{ //c,d 会自动合并在一起的
int a=1;
int b=2;
}
namespace shuai
{
int c=3;
int d=4;
}
using namespace shuai;
int main()
{
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
printf("%d\n", d);
return 0;
}
最后 以后我们写一些大型的项目时候一般不把std全部展开,但是我们目前的阶段可以展开,所以我们在初学c++时可以使用: using namespace std
我们举个列子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LaogGvYm-1689596957594)(C:\Users\lao\AppData\Roaming\Typora\typora-user-images\image-20230717120246143.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtyGXfEI-1689596957594)(C:\Users\lao\AppData\Roaming\Typora\typora-user-images\image-20230717120025993.png)]
区别就是:缺省参数给形参赋值了,a,b 叫形式参数, c , d 叫缺省参数
void Func(int a = 10, int b = 20, int c = 30)//形参全部赋值
{
cout<<"a = "<
全缺省就是函数的形参全部给了值
特点
#include
using namespace std;
// 全缺省
void func(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main()
{
func(); //一个值都不传,那就是形参默认的值
// 显示传参,从左往右显示传参
func(1); //只传一个值,那这个值会被赋给a,其他的是形参默认的值
func(1,2); //传两个值,a = 1, b = 2; c就是形参的那个值
func(1, 2, 3); // 传3个值,a = 1, b = 2, c = 3;
return 0;
}
void Func(int a, int b = 10, int c = 20)//形参部分赋值
{
cout<<"a = "<
半缺省就是函数的形参没有完全给值
特点
// 半缺省 -- 必须从右往左,给缺省值
void Func(int a, int b = 10, int c = 20) //意思就是半缺省,你给形参赋值,必须从右往左赋值
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
注意 如果你用缺省参数时是将声明和定义分开的,那么它们不能同时给缺省参数
比如:
//第一种写法
//函数的声明
int add(int a = 1, int b = 2); //声明是给了缺省参数的
//函数的定义
int add(int a = 1, int b = 2) //定义又给了缺省参数的
{
return a + b;
}
//第一种写法是错的,因为声明和定义同时给了缺省参数
//可以改成第二种写法:声明给,定义不给
int add(int a = 1, int b = 2); //声明是给了缺省参数的
//函数的定义
int add(int a , int b ) //定义就不给缺省参数了
{
return a + b;
}
函数重载类似于语文的一词多意
语文中的一个词可以表示很多不同意思
c++的一个函数可以实现不同的功能
这就是函数重载
函数重载的要求:
注意
函数的返回值不同是不能构成重载的
注意
要构成函数重载要在同一个域中才行
比如:
namespace test1
{
int add(int a);
}
namespace test2
{
int add(double a);
}
//上面的两个add就不构成函数重载,因为他们在不同的域中,(不同的命名空间是不同的域)
注意
函数重载和缺省参数没有关系