一、前言
我们知道c++是对c语言的完善以及再发展,所以C++中的很多东西是与C语言十分修饰的,并且C++也是兼容C的,学习了C之后,相信学C++也不在困难,对我们来说,唯一感到不解和陌生就只有 using namespace std; 这条语句,要理解这条语句,我们需要学习C++的命名空间相关知识。
C++的第一个程序:
#include<iostream> //IO流头文件
using namespace std; //全局展开std命名空间
int main()
{
// cout 是输出函数
// << 流插入运算符,配合 cout 使用
// endl 换行符,相当于 \n
cout << "Hello World!" << endl;
return 0;
}
二、命名空间
1、什么是命名空间?
看看这一段代码:
#include<stdio.h>
#include<stdlib.h>
int rand = 10;
int main()
{
printf("%d ", rand);
return 0;
}
//运行后会报错:error C2365 : “rand”: 重定义;以前的定义是“函数”
这里报错的问题是我们定义的变量与库里函数名的rand函数名称发生了冲突,在C语言中这样的问题是没有办法解决的,而在C++中这类问题我们可以通过命名空间得以解决。使用命名空间的目的是对标识符的名称进行本地化, 以避免命名冲突或名字污染,其中定义命名空间的关键字是 namespace。
2、命名空间的定义
#include<iostream> //IO流头文件
using namespace std; //全局展开std命名空间
//命名空间
namespace A
{
//定义变量
int num = 10;
//定义类型
typedef struct SLNode
{
int data;
struct SLNode* next;
}SLNode;
//定义函数
int ADD(int a, int b) {
return a + b;
}
}
namespace B
{
//定义变量
int num = 24;
//定义类型
typedef struct SLNode
{
int data;
struct SLNode* next;
}SLNode;
//定义函数
int ADD(int a, int b) {
return a + b;
}
}
int main()
{
//不同命名空间内的同名 变量/函数 不冲突
cout << A::num << endl;
cout << B::num << endl;
cout << A::ADD(1,3) << endl; //::域作用限定符,指定为A空间里的函数
cout << B::ADD(3, 4) << endl;
return 0;
}
输出结果:
此时我们可以看懂这行代码了:
using namespace std; //全局展开std命名空间
它的作用是展开std这个命名空间,即库函数,只有展开后,我们才可以正常使用cout与endl。
有三种方法使用命名空间:
用using将命名空间全局展开(在做项目时不建议使用,做练习时可以)
利用::指定命名空间( 一般做项目时使用此方式)
用using +::将命名空间常用展开
三种方法的代码使用场景(以std域为例):
//命名空间全局展开
using namespace std;//std为C++标准库
//指定命名空间
std::cout << "hellow world\n" << std::endl;
//命名空间常用展开
using std::cout;
using std::endl;
最上面的C程序rand函数加个域在C++环境中就可以正常使用了。
三、缺省参数
1、缺省参数的概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值;在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参。
void Func(int a = 10) {
cout << a << endl;
}
int main() {
Func(2); //有传参时,使用参数的指定值
Func(); //没有传参时,使用参数的默认值
return 0;
}
2、缺省参数的分类
缺省参数一共分为两类:全缺省参数和半缺省参数;
全缺省参数:
void Func(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
半缺省参数:
void Func(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
3、缺省参数的规则
1、只允许从右到左依次连续缺省,不得出现跳跃缺省
//正确用法
void test(int a, int b = 2, int c = 3); //从右至左,连续缺省
//错误用法
void test(int a = 1, int b, int c); //非从右至左缺省
void test(int a, int b = 2, int c); //跳跃缺省,非法
2、调用时,实参依次从左往右传递
//正确用法
test(4,5,6); //不启用缺省值,a = 4,b = 5, c = 6
test(5,6); //启用缺省参数 c,a = 5, b = 6, c = 3
//错误用法
test(); //此时必须传一个参数,因为参数 a 不是缺省参数
test(1,2,3,4); //参数传多了
3、声明和定义中不能同时出现缺省参数,只能在声明中出现
//test.h
//声明时缺省
void test(int a = 10);
//test.c
//定义时不必再缺省
void test(int a)
{
cout << a << endl;
}
四、函数重载
1、函数重载的概念
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
//C语言
int Add(int x, int y);
double Add(double x, double y); //此时会报错,两个函数名冲突
//C++
int Add(int x, int y);
double Add(double x, double y); //正常编译,即使函数名都是Add,但在C++中编译器能分清两者
2、函数重载的原理
我们在学习C语言 程序环境和预处理 的时候知道了一个程序要运行起来,需要经历预处理、编译、汇编、链接四个阶段;其中编译阶段会进行符号汇总,汇编阶段会生成符号表,而链接阶段则会对符号表进行合并与重定位,其中符号表会将每一个变量都关联上一个地址,但这个地址是否有效需要在链接阶段进行符号表的合并与重定位是时才能检查出来。
我们可以在Linux环境下,通过objdump -S来查看函数的修饰情况,显然,C和C++的修饰情况是不同的。
C环境下:
C++环境下:
在底层原理下可以发现,C++中对函数名的修饰为_Z3ADDii,_Z是修饰前缀,3为函数名长度,ADD即为函数名,ii代表参数名的类型,即int,int。C++相较于C语言来说修饰的更加全面。Linux下修饰函数名简单,而window下修饰函数名就比较复杂了。
3、构成重载的三种方式
1、参数类型不同
// 1、参数类型不同
//都为int
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
//都为double
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
int main()
{
Add(1,2);//3
Add(1.1.2.2);//3.3
//不会报错,但如果是在C语言的环境下,则会报错:Add重定义,具体原因后面会讲
return 0;
}
2、参数个数不同
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
int main()
{
f();//f()
f(1);//f(int a)
}
3、参数的类型顺序不同
//int 在前char在后
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
//char在前,int 在后
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
注意: 返回值不纳入函数名修饰中,假若加入,函数调用时就会出现混乱,因此返回值不同并不构成函数重载