目录
命名空间
命名空间定义
命名空间使用
法一:加命名空间名称及作用域限定符::
法二:使用using部分展开(授权)某个命名空间中的成员
法三:使用using对整个命名空间全部展开(授权)
C++输入&输出
std命名空间的使用惯例:
缺省参数
缺省参数分类
全缺省参数:所有的参数都有指定的缺省值
半缺省参数:部分参数有指定缺省值
缺省参数的作用
函数重载
编辑 C++支持函数重载的原理
总结:C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载
命名空间
C/C++中,变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突
命名空间定义
关键字是namespace,后面跟名字,命名空间的名字可以任意取,然后{},里面是命名空间的成员
1 命名空间中可以定义变量/函数/类型
namespace N1
{
int rand = 10;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
}
2 命名空间可以嵌套
namespace N1
{
int rand = 10;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
namespace N2
{
int a = 9;
}
}
3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会将它们合并成同一个命名空间
如一个工程中的test.h和test.cpp中的两个N1会被合并成一个
//test.cpp中的命名空间N1
namespace N1
{
int rand = 10;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
int a = 9;
}
//test.h中的命名空间N1
namespace N1
{
int b = 6;
}
一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
命名空间使用
定义在命名空间中的成员若没有授权是无法被搜索到的,那要使用命名空间中的成员有如下三种方法
法一:加命名空间名称及作用域限定符::
namespace N1
{
int rand = 10;
int Add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
int a = 9;
}
int main()
{
cout << N1::Add(1, 3) << endl;
cout << N1::a<< endl;
return 0;
}
法二:使用using部分展开(授权)某个命名空间中的成员
展开常用的库对象/类型,这样就不用每次都要像法一一样了
using N1::a;
int main()
{
cout << a<< endl;
return 0;
}
法三:使用using对整个命名空间全部展开(授权)
using namespace N1;
int main()
{
cout << a<< endl;
return 0;
}
C++输入&输出
std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
而早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应
头文件即可,后来将其实现在std命名空间下
使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std
endl:换行,cout、cin、endl都包含在<iostream >头文件中
<<是流插入运算符,>>是流提取运算符
#include<iostream>
using namespace std;
int main()
{
cout << "hello world"<<endl;
return 0;
}
C++输入输出更方便,不需要手动控制格式,它的输入输出可以自动识别变量类型
#include<iostream>
using namespace std;
int main()
{
int a = 0;
double b = 0;
cin >> a >> b;
cout << a<<endl;
cout << b << endl;
return 0;
}
std命名空间的使用惯例:
日常练习中,可以直接using namespace std即可,比较方便
using namespace std展开,是对std的全部展开(授权),那么标准库就全部暴露出来了,若我们定义跟库重名的类型/对象/函数,就存在冲突问题。而在日常练习中很少出现,所有可以全部展开(授权),但是项目开发中就不要全部展开了,因为代码多,很容易出现命名冲突,可以用命名空间使用的另外两种方法
缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实
参则采用该形参的缺省值,否则使用指定的实参
缺省参数不能在函数声明和定义中同时出现,声明给,定义不给
因为若声明和定义同时出现缺省参数,且恰巧两个位置给定的值不同,那编译器就无法确定到底该
用那个缺省值
void func(int a = 4)
{
cout << a << endl;
}
int main()
{
func();
func(9);
return 0;
}
缺省参数分类
全缺省参数:所有的参数都有指定的缺省值
void func(int a = 4,int b = 5,int c= 6)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
func();
return 0;
}
注意:显示传参,需要从左往右传参
半缺省参数:部分参数有指定缺省值
半缺省,必须从右往左给缺省值,不能间隔着给
void func(int a,int b = 5,int c= 6)
{
cout << a << endl;
cout << b << endl;
cout << c << endl << endl;
}
int main()
{
func(1);
func(1, 4);
func(1, 4, 7);
return 0;
}
缺省参数的作用
比如用在开辟栈的数组空间的时候,默认开4个,如果你知道自己需要100个空间,那就可以开100个
//stack.h
namespace N1
{
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void STInit(ST* pst,int N = 4);//声明给缺省参数,默认开4个空间
void STPush(ST* pst,int x);
}
//stack.c
void N1::STInit(ST* pst, int N)
{
pst->a = (int*)malloc(sizeof(int) * N);
pst->top = 0;
pst->capacity = 0;
}
int main()
{
N1::ST st;
STInit(&st,100);//传入100,那就由原来默认的开4个空间变成开100个空间
int i = 0;
for (i = 0; i < 100; i++)
{
STPush(&st, i);
}
return 0;
}
函数重载
简单来说,函数重载就是一个函数名有多个功能,就像一词多义
c语言不支持函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这
些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型
不同的问题
1 参数类型不同
//参数类型不同
int Add(int x, int y)
{
cout << "int Add(int x, int y)"<<endl;
return x + y;
}
double Add(double x, double y)
{
cout << "double Add(double x, double y)" << endl;
return x + y;
}
int main()
{
Add(3,4);
Add(3.3,4.4);
return 0;
}
2 参数个数不同
//参数个数不同
void func()
{
cout << "func()" << endl;
}
void func(int a)
{
cout << "func(int a)" << endl;
}
int main()
{
func();
func(3);
}
3 参数类型顺序不同
//参数类型顺序不同
void f(int x, char y)
{
cout << "f(int x, char y)" << endl;
}
void f(char x, int y)
{
cout<< "f(char x, int y)" << endl;
}
int main()
{
f(3, 4.4);
f('A', 8);
return 0;
}
两个函数函数名和参数是一样的,但返回值不同是不构成重载的,如以下情况
因为调用时编译器没办法区分,c++的函数名修饰规则不关返回值的事
C++支持函数重载的原理
c语言是不支持函数重载的,那为什么c我们知道一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接
对于c:若是认为c能够支持函数重载,那么我们就会在同一个文件内定义两个同名不同功能的函数,在编译时,会进行全局变量的符号汇总,c语言会直接用函数本身的名字,可能会稍微加一些小改变,比如有f函数,那就变成_f,下面可以看到f变成了_f
那么两个同名的函数,在编译时进行符号汇总,就会在同一个文件内搜集到相同的两个名字,比如_f和_f
在汇编形成符号表时,形成符号名+地址的映射关系
在链接时,会进行符号表的合并和重定位,那这个时候问题就来了,两个相同名字,却各自有地址,链接时到底用谁?
对于c++:c++有函数名修饰规则,即使时相同名字的函数,在编译时会根据函数形参的类型对原本的函数名进行修饰
我声明了两个函数名相同的函数f,参数不同
在vs中:
我们可以看到原本函数名f变成了复杂的名字,一个函数名f变成了
另一个函数名f变成了
区分就是第一个是HD,第二个是DH,H用来代表参数的int类型,D代表参数的char类型
vs中的修饰规则比较复杂,那我们用Linux来演示
在Linux下g++中:g++的函数修饰后变成【_Z+函数长度+函数名+类型首字母】
函数名Add变成了_Z3Addii ,把Add的参数类型加入名字修饰中
函数名func变成了_Z4funcidiPi ,把func的参数类型加入名字修饰中
所以C++存在的函数名修饰规则,会在编译时为名字相同但功能不同的函数给出不同的名字
因为函数重载的特性就是同一作用域下的同名函数,形参列表(参数个数 或 类型 或 类型顺序)不同,那就肯定修饰的名字不同
故而链接时可以区分,不会发生冲突