命名空间
命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{} 中即为命名空间的成员
命名空间的使用
1.命名空间成员访问:命名空间名 + ::+ 变量名/函数名
例1:
namespace N1 {
int b;
int sub(int a, int b) {
return a - b;
}
namespace N2 {
int b;
}
}
void test1() {
N1::b = 10;
N1::sub(10, 5);
//嵌套
N1::N2::b = 5;
}
2.命名空间成员访问:using + 命名空间名 +::+ 变量名/函数名
使用时不需要再加作用域,但在函数外部声明
例2:
namespace N1 {
int b;
int sub(int a, int b) {
return a - b;
}
namespace N2 {
int b;
}
}
using N1::b;
using N1::sub;
using N1::N2::b;
void test1() {
b = 10;
sub(10,5);
b = 5;
}
3.引入整个命名空间:using space + 命名空间名
例3:
namespace N1 {
int b;
int sub(int a, int b) {
return a - b;
}
namespace N2 {
int b;
}
}
using namespace N1;
void test1() {
b = 10;
sub(10,5);
b = 5;
}
注意:不推荐用这种方式,可能会造成变量重复(污染)。
C++输入输出
例4:
#include<iostream>
void testIO() {
printf("!");
int a = 0;
double b = 0;
//对比c语言
//scanf("%d",&a);
//scanf("%lf",&b);
//输入
std::cin >> a;
std::cin >> b;
//输出
std::cout << a;
std::cout << '\n';
std::cout << b;
}
int main() {
testIO();
return 0;
}
例5:
#include<iostream>
using namespace std;
void testIO() {
int a = 0;
double b = 0;
cin >> a >> b;
cout << a << ' ' << b << endl;
}
int main() {
testIO();
return 0;
}
从上例可以看到:
c++的输入不需要格式,相比c语言更加精简,面向对象
cin,cout从左向右连续输入输出
缺省参数
概念
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实 参则采用该默认值,否则使用指定的实参。
使用
- 没有传参时,使用参数的默认值
- 传参时,使用指定的实参
例六:
void fun(int a = 100, int b = 0) {
cout << a << ' ' << b << endl;
}
int main() {
fun();
fun(1, 2);
return 0;
}
//输出:
//100 0
//1 2
半缺省参数与全缺省参数
例5例6都为全缺省参数型
例7.半缺省参数使用
void fun(int a, int b = 0) {
cout << a <<' '<< b << endl;
}
int main() {
fun(1, 2);
fun(1);
}
//输出:
//1 2
//1 0
- 半缺省参数:缺省值从右到左连续赋值
即:缺省值应该在非缺省值的右边
- 缺省值只能在一个地方定义(声明中或者定义中)
例8.
// 非缺省值在左端 缺省值在右边
void fun(int a, int b = 0, int c = 0) {
cout << a << ' ' << b << ' ' << c << endl;
}
int main() {
fun(1, 2, 3);
fun(1, 2);
fun(1);
}
例9
void fun(int a = 5) {
;
}
//或
void fun(int a = 0);
void fun(int a) {//这时不能在定义中再次定义这个缺省参数
;
}
缺省值必须时常量或者全局变量
函数重载
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数
这些 同名函数的形参列表(参数个数 或 类型 或 类型顺序)必须不同,常用来处理实现功能类似数据类型不 同的问题
例10
//参数类型不同
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
cout << add(1, 2) << ' ' << add(1.2, 2.0) << endl;
}
//输出
//3 3.2
//参数个数不同
int add(int a, int b, int c) {
return a + b + c;
}
int add(int a, int b) {
return a + b;
}
int main() {
cout << add(1, 2, 3) << ' ' << add(1, 2) << endl;
}
//输出
//6 3
//参数类型顺序不同
void Print(char c, int a) {
cout << c << ' ' << a << endl;
}
void Print(int a, char c) {
cout << a <<' '<< c << endl;
}
int main() {
Print('a', 1);
Print(1, 'a');
}
//输出
//a 1
//1 a
总结:
- 函数名相同
- 返回值不同不构成函数重载
- 作用域不同不构成函数重载
判断:以下函数构成函数重载吗?
short Add(short left, short right)
{
return left+right;
}
int Add(short left, short right) {
return left+right;
}
为什么c++可以有函数重载而c语言没有呢? 这就牵扯到了下个知识点——名字修饰
名字修饰
首先我们看一下函数名在c与c++底层的不同
再看这一组:
vs编译器:
函数名编译:sub(int a,int b)
c底层:_sub -----------> _sub
c++底层:?sub@@YAHHH@Z ---------> ?sub@@YAHMH@Z
由此可知:
C语言不支持函数重载是因为C语言的函数名修饰规则不支持,因为只要函数名相同,底层的函数名就是相同的,从而无法区分。
而C++的底层函数名修饰规则要复杂的多,它由前缀+函数名+参数信息构成,从而即使函数名相同,底层的函数名是不同的,这样这些重载的函数时可以区分的。
extern "C"{}
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告 诉编译器,将该函数按照C语言规则来编译
以下两个函数是函数重载吗? (不是)
void TestFunc(int a = 10)
{
cout<<"void TestFunc(int)"<<endl;
}
void TestFunc(int a) {
cout<<"void TestFunc(int)"<<endl;
}
引用
概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间
使用
类型& 引用变量名(对象名) = 引用实体
1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
4.引用类型必须和引用实体是同种类型的
例11
void testRef() {
int a = 10;
int copy = a;
int& ra = a;
ra = 100;
copy = 1000;
cout << a << endl;
}
//输出
//100
int main() {
testRef();
}
void testRef() {
int a = 10;
int b = 20;
int& ra = a;
int& rra = a;
int& rrra = a;
ra = 100;
cout << a << endl;
rra = 1000;
cout << a << endl;
rrra = 10000;
cout << a << endl;
ra = b;
cout << a << endl;//改变的是ra的值也就是a的值
}
//输出
//100
//1000
//10000
//说明一个变量可以有多个引用
int main() {
testRef();
return 0;
}
引用是变量的别名
常引用
void testRef() {
int c = 10;
const int& rc = 10;//指向常量
const int d = 5;
const int& rd = d;
float f = 2.0;
const int& rf = f;
//浮点数赋值给整形时会进行隐式类型转换,2.0 转化为 2,
//这个2是一个临时变量,它无法被修改,因此它具有常量的性质,因此需要加上const指向这个常量
}
int main() {
testRef();
return 0;
}
引用实例
例12
void Swap(int* a, int* b) {
int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
}
void Swap(int& a, int& b) {
int tmp = 0;
tmp = a;
a = b;
b = tmp;
}
int main() {
int a = 1;
int b = 2;
Swap(&a, &b);
Swap(a, b);
printf("%d %d", a, b);
return 0;
}
//输出
//1 2
//证明引用有与指针同样的功能
引用类型返回值
int& SelfAdd(int& a) {
a++;
return a;
}
int main() {
int a = 0;
int& ra = SelfAdd(a);
cout << a << endl;
return 0;
}
//输出
//1
注意:
请看下面的代码:你觉他它会输出5吗?
int& add(int& a, int& b) {
int c = a + b;
return c;
}
int main() {
int a = 2;
int b = 3;
int& sum = add(a, b);
cout << a << ' + ' << b << ' = ' << sum << endl;
}
//输出一个任意值
为什么会这样?请看下图
所以我们在使用引用时要注意引用的变量的生命周期要大于函数的生命周期
改为:
int& add(int& a, int& b,int& c) {
c = a + b;
return c;
}
int main() {
int a = 2;
int b = 3;
int c = 0;
int& sum = add(a, b,c);
cout << a << ' + ' << b << ' = ' << sum << endl;
}
效率问题:
我们看一下下面这个代码,大家猜一猜他们俩的处理时间会相差多少?
struct A {
int arr[100000];
};
void testValue(A a) {
}
void testRef(A& ra) {
}
int main(){
A a;
int i = 0;
size_t begin,end;
begin = clock();
//因为程序跑的太快,所以我们用循环来增加他们跑的时间方便我们更具体的观察比较
for(i = 0;i<1000000;i++)
testValue(a);
end = clock();
cout << "testValue :" << (end - begin)/CLOCKS_PER_SEC << endl;
begin = clock();
for (i = 0; i < 1000000; i++)
testRef(a);
end = clock();
cout << "testRef :" << (end - begin)/ CLOCKS_PER_SEC << endl;
//(end - begin)/ CLOCKS_PER_SEC 计算程序运行的秒数
}
//输出
//testValue:25
//testRef : 0
引用和指针的区别
引用用指针实现,本质就是指针
引用和指针的不同点:
1. 引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
3. 没有NULL引用,但有NULL指针
4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全
以上就是本次的所有内容,有什么不足欢迎指教!
对您有帮助不妨点一个赞!