前面我们一直在和C打交道,C语言作为最开始学习的语言,大家在学习过程中可能会感到有一些它本身的一些的麻烦和不便,为了使C语言更加方便和完善,人们在C的基础上更加完善,便诞生了C++
我们今天来了解一下C++的入门:
命名空间
在学校学习过C++的老铁们肯定会对这段代码无比熟悉:
#include<iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
这是用C++写的hello world,我在学习的时候我一直都有一个问题:为什么C++写代码的时候总要加一句using namespace std;?
其实这是为了解决C语言中的一个问题:重名,我们经常在定义函数或者变量的时候,在不够了解的情况下,我们自己创建的函数或变量会和库函数中的函数和变量相冲突。
我们来看个列子:
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
printf("%d ", rand);
return 0;
}
这段代码会报错,是因为stdblib.h的头文件中有一个函数名为rand的函数,我们又定义了rand,会发生重名,但C语言没有办法解决。
所以为了解决这个问题,C++创建了命名变量namespace来解决问题
namespace 的语法格式是:namespace + XXX(名字)
namespace _rand
{
int rand = 0;
}
int main()
{
printf("%d ", _rand::rand);
return 0;
}
上面的printf的意思是:打印_rand里面的rand其中 : :是域作用限定符
如果我不加_rand::
namespace _rand
{
int rand = 0;
}
int main()
{
printf("%d ", rand);
return 0;
}
如果不加,编译器就会在全局找,就不会进去_rand里面去找。
我们也可以让程序跑起来证明:
因为rand是一个函数,在printf里rand是函数名,是函数的地址,我们用%d去打印会报类型不匹配
在namespace中可以写:变量,函数,结构体。
int a = 1;
int Add(int x, int y)
{
return x + y + 10;
}
struct Node
{
int data;
struct Node* next;
int size;
};
namespace Space
{
int a = 99;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int data;
struct Node* next;
};
}
int main()
{
printf("全局%d\n", a);
printf("namespace中%d\n", Space::a);
printf("全局%d\n", Add(2, 3));
printf("namespace中%d\n", Space::Add(2, 3));
return 0;
}
结构体我们看看:
namespace展开方式
全展开
如果我们想用命名空间,我们每次都得用域作用限定符,非常不方便,这时候我们可以将命名空间展开。
我们先来看全展开:using namespace XXX:
//int a = 1;
//
//int Add(int x, int y)
//{
// return x + y + 10;
//}
//
//struct Node
//{
// int data;
// struct Node* next;
// int size;
//};
namespace Space
{
int a = 99;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int data;
struct Node* next;
};
}
using namespace Space;
int main()
{
printf("%d\n", a);
printf("%d\n", Add(2, 3));
//struct Node N1;
N1.
//struct Space:: Node N2;
N2.
return 0;
}
using namespace Space说白了:将Space里面的东西放出来了
using namespace Space效果就是下面这段代码的效果:
//int a = 1;
//
//int Add(int x, int y)
//{
// return x + y + 10;
//}
//
//struct Node
//{
// int data;
// struct Node* next;
// int size;
//};
int a = 99;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int data;
struct Node* next;
};
int main()
{
printf("%d\n", a);
printf("%d\n", Add(2, 3));
//struct Node N1;
N1.
//struct Space:: Node N2;
N2.
return 0;
如果我们把注释代码撤销注释,编译器会报错:
int a = 1;
int Add(int x, int y)
{
return x + y + 10;
}
struct Node
{
int data;
struct Node* next;
int size;
};
namespace Space
{
int a = 99;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int data;
struct Node* next;
};
}
using namespace Space;
int main()
{
printf("%d\n", a);
printf("%d\n", Add(2, 3));
/*struct Node N1;
N1.*/
//struct Space:: Node N2;
N2.
return 0;
}
特定展开
除了全展开,还有特定展开:using XXX::XXX
int a = 1;
int Add(int x, int y)
{
return x + y + 10;
}
struct Node
{
int data;
struct Node* next;
int size;
};
namespace Space
{
int a = 99;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int data;
struct Node* next;
};
}
using Space::Add;
int main()
{
printf("%d\n", a);
printf("%d\n", Add(2, 3));
/*struct Node N1;
N1.*/
//struct Space:: Node N2;
N2.
return 0;
}
这段代码也会报错,因为它可以等同于下面这段代码
int a = 1;
int Add(int x, int y)
{
return x + y + 10;
}
struct Node
{
int data;
struct Node* next;
int size;
};
namespace Space
{
int a = 99;
struct Node
{
int data;
struct Node* next;
};
}
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("%d\n", a);
printf("%d\n", Add(2, 3));
/*struct Node N1;
N1.*/
//struct Space:: Node N2;
N2.
return 0;
}
我们会发现,命名空间如果随意展开有可能又会出现重名问题,所以一般来说我们不会随意展开命名空间。
这下我们可以来解释我们最开始的using namespace std;:展开std的命名空间其中std为C++标准库,其中std中就包含的有输出cout,和输入cin。
了解原理之后,我们打印hello world就有另外一种写法:
int main()
{
std::cout << "hello world" << std::endl;
}
我们还可以部分展开:
using std::cout;
int main()
{
cout << "hello world" << std::endl;
}
再提一点:同名的命名空间可以合并
using namespace std;
namespace Space1
{
int a = 99;
int b = 100;
}
namespace Space1
{
int Add(int x, int y)
{
return x + y;
}
}
int main()
{
cout << Space1::
}
缺省参数
我们在C语言中,经常会写函数:
int Add(int x,int y)
{
return x + y;
}
int main()
{
int ret=Add(2, 3);
}
那有没有一种可能:函数的形参可以被赋值。
using namespace std;
int Add(int x = 1,int y = 2)
{
return x + y;
}
int main()
{
int ret=Add(2, 3);
cout << ret << endl;
}
我们看看结果:
如果我不传值呢?:
using namespace std;
int Add(int x = 1,int y = 2)
{
return x + y;
}
int main()
{
int ret=Add();
cout << ret << endl;
}
我们可以看出来缺省参数的定义:函数的形参有初值。并且一个函数有缺省参数,若函数有传真值过来,函数则以真值进行计算,如果没有传值,则会以缺省值进行计算
并且缺省有两种形式:
全缺省:函数的形参全部都有赋值
int Add(int x = 1, int y = 2)
{
return x + y;
}
半缺省:函数的形参部分有赋值,并且半缺省参数必须从右往左依次来给出,不能间隔着给
int Add(int x , int y = 2,int z = 10)
{
return x + y + z;
}
同时要注意:不能缺位给值和缺省参数不能在函数声明和定义中同时出现
int main()
{
int ret = Add(1);//合法
int ret1=Add(,2,3) //不合法,形参1没给值,就给形参2和形参3给值
cout << ret << endl;
}
函数重载
函数重载,简单来说就是一词多义,相同的函数名有着不同的功能。
using namespace std;
int Add(int x , int y)
{
return x + y;
}
double Add(double x, double y)
{
return x + y;
}
int main()
{
int ret1 = Add(1,2);
double ret2 = Add(2.3, 3.5);
cout << ret1 << endl;
cout << ret2 << endl;
}
函数重载的条件是:同名函数的形参列表(参数个数 或 类型 或类型顺序不同)
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}