【C++】C++基础 (C++关键字 命名空间 输入输出 缺省参数 函数重载)


前言,我们C++这门语言,兼容C语言,C++是C语言的升级。

1.C++关键字

C++总计63个关键字,C语言32个关键字

在这里插入图片描述

2.命名空间

我们先使用C++来写一个"hello world"

#include<iostream>
using namespace std;
int main()
{
	cout << "hello world" << endl;
	return 0;
}

或者

#include<iostream>

int main()
{
	std::cout << "hello world" << std::endl;
	return 0;
}

这两种写法主要涉及两个知识,一个是IO流,另一个是命名空间,
C++在设计初期就是为了解决C语言的一些不足,C语言第一个不足之处就是名字冲突,什么是名字冲突?

#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
	printf("hello world\n");
	printf("%d\n", rand);
	return 0;
}

这个代码一编译,就出问题了,在这里插入图片描述
这个问题叫重定义,rand重定义,因为我们定义的rand和#include<stdlib.h>库里面的rand重定义,库里的rand是一个函数,我们定义的rand是一个变量,我们自己定义的变量和库的函数名冲突了,这就叫做命名冲突问题,C++为了解决这个问题,引入了一个概念叫做命名空间。

namespace是C++中的一个关键字,和struct类似,用它可以定义命名空间,,命名空间可以随便定义,我们把我们定义的rand放到命名空间里去,此时就不会冲突了,

#include<stdio.h>
#include<stdlib.h>

namespace bit
{
	int rand = 0;
}
int main()
{
	printf("hello world\n");
	printf("%d\n", rand);
	return 0;
}

因为命名空间已经把它隔离起来了,我们平时搜索变量会在全局搜索,全局有两个rand,此时肯定就会报错,现在有一个rand在命名空间bit里面,就不会冲突,

	printf("%d\n", rand);

这个里面的rand默认访问的是库里的。此时我们想访问命名空间的怎么办?C++中有一个叫做域作用限定符,rand这个变量属于bit这个域,若我们想访问的话,我们可以指定访问bit这个命名空间。

printf("%d\n", bit::rand);

为了更好的防止冲突,C++定义了一种叫 std 的东西,C++标准库的东西放进了std命名空间。

#include<iostream>
int main()
{
	std::cout << "hello world" << std::endl;
	return 0;
}

C语言printf是打印字符串或者指定你要打印什么格式,C++中

std::cout << "hello world" << std::endl;

这个叫IO流,可以自动识别类型,不同类型可以拼在一起。

问题:rand是全局变量还是局部变量?

namespace bit
{
	int rand = 0;
}

它是一个全局变量,只有一种变量是局部变量,只有定义在函数中的变量是局部变量,局部变量的特点是它存在栈上,因为它在栈帧里面,在函数调用的时候会建立栈帧,函数结束栈帧销毁,变量也就随之销毁了。命名空间中建立的变量并不是在函数栈帧上的,它和在全局建立的rand是一样的,只是为了防止冲突,把它放在域里面,影响的只是它的查找规则,命名空间不影响生命周期,只是一个限定域,影响的是查找规则。

命名空间里面除了定义变量还可以定义函数、类型

直接定义,和定义在命名空间的区别是什么?
区别就是,放在全局的话,可以看成就是种了一片果树,谁都能摘,加了命名空间就是加了个围墙,如果是全局的我们就直接可以调用,
否则我们就要用指令进行访问。

namespace bit
{
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}

int main()
{
	printf("%d\n", bit::Add(1, 2));
	
    struct bit::Node node;
	return 0;
}

用围墙围起来的好处是为了防止跟别人冲突。访问谁就指定谁,互相不会干扰,避免了命名冲突。

namespace bit
{
	int Add(int left, int right)
	{
		return left + right;
	}

	struct Node
	{
		struct Node* next;
		int val;
	};
}

namespace byte
{
	int Add(int left, int right)
	{
		return left*10 + right*10;
	}

	struct Node
	{
		struct Node* next;
		struct Node* prev;
		int val;
	};
}
int main()
{
	printf("%d\n", bit::Add(1, 2));
	printf("%d\n", byte::Add(1, 2));

	struct bit::Node node;
	struct byte::Node dnode;
	return 0;
}

还有就是,命名空间里面还可以嵌套命名空间,

namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}

int main()
{
	//访问a,c
	N1::a = 1;
	N1::N2::c = 2;
	return 0;
}

里面的变量都是全局的,只是访问略有差别。

我们为了避免冲突C++把标准库里的东西都定义在了它官方的一个命名空间,这个命名空间的名字叫std(C++官方库内容定义的命名空间),官方库里的东西能不能只定义在一个文件里面?不能,C++允许定义同名的多个命名空间,它定义在多个文件,多个文件它会自动合并。

同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

既然标准库把它们的东西都定义在命名空间里去,我们每次打印东西,这样写是很麻烦的,

#include<iostream>
int main()
{
	std::cout << "hello world" << std::endl;
	return 0;
}

所以命名空间又开发了一种简单的使用方式,这种方式叫

#include<iostream>
using namespace std;
int main()
{
	cout << "hello world" << endl;
	return 0;
}

这种方式的意义就是把命名空间里面的内容给展开,默认不指定,编译器是编译不过的。这种方式的好处就是用起来方便了,相当于把命名的隔离墙给拆了,那这种写法有什么坏处呢?
自己定义变量时容易冲突。

所以,我们建议日常练习,写个小程序,这么用可以,项目最好不这样用。在项目用的时候我们也不需要那么死板,我们可以不拆墙,进行部分展开或者叫指定展开,我们可以这样

#include<iostream>
//指定展开
using std::cout;
using std::endl;

int main()
{
	cout << "hello world" << endl;
	return 0;
}

这种方式我们可以把常用的展开,自己定义的时候避免跟常用的重名即可。尽量避免全部展开,全部展开是有很大的风险的。

3. C++输入&输出

cout我们目前讲不清楚,因为cout是一个对象,我们后面讲它的原理,现阶段我们就记住,理解一个形象的说法。cout我们可以认为它就是那个控制台,我们写一个hello world可以这样写:

	cout << "hello world!" << endl;

hello world!这个字符串流向cout这个对象里面去,这个对象就是控制台,endl代表的是换行。特点就是自动识别类型,

cin >> a;

cin是流提取,指输入的东西从cin里面拿到,也可以自动识别类型
在这里插入图片描述
可以结合C语言输出。哪个方便用哪个。

注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应 头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用 < iostream > +std的方式。

4. 缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

#include <iostream>
using namespace std;
void Func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	Func();
	Func(10);
	return 0;
}

有了这个缺省值,我们可以传参,也可以不传参,如果不传,a的值是0,传的话就没有缺省值的事了,10作为实参传给形参a。
缺省参数扩展一下,如果有多个缺省参数呢?
可以都给缺省值,

void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{
	Func();
	Func(1);
	Func(1,2);
	Func(1, 2,3);
	return 0;
}

调用这个函数可以怎么调呢?
第一种:一个都不传,全部用缺省值。

Func();

第二种:可以传一个,这一个值是传给a的,默认从左往右传,b、c还用的是缺省值。

Func(1);

第三种:传两个值,一样是从左往右依次传,不能跳着传。

Func(1,2);

最后一种就是全传

Func(1,23);

到底是从左往右传还是从右往左传,这个都是不一定的,要看编译器平台。

全部缺省叫全缺省,它的调用非常灵活。除了全区缺省,根据需求还可以半缺省,

void Func(int a, int b = 10, int c = 20)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{
	Func(1);
	Func(1,2);
	Func(1,2,3);
	return 0;
}

此时半缺省我们就不能不传,传一个相当于传给a,传三个相当于缺省值一个也没用。

注意:部分缺省只能从右往左连续缺省。

这样是不可以的:

void Func(int a, int b = 10, int c)

缺省参数有一个特点,就是不能在函数声明和定义中同时出现,在声明中给。缺省值必须是常量或者全局变量。

5. 函数重载

一个词可以有多重含义,人们可以通过上下文来判断词真是的含义,即该词被重载了。

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明及格功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

int add(int x, int y)
{
	return x + y;
}

double add(double x, double y)
{
	return x + y;
}

int main()
{
	cout << add(1, 2) << endl;
	cout << add(1.1, 2.2) << endl;
	return 0;
}

C语言是不允许这俩函数同时存在的,C++可以,但是也有一些要求。
要求:函数名相同,参数不同(个数、类型、顺序)

void swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}

void swap(double* px, double* py)
{
	double tmp = *px;
	*px = *py;
	*py = tmp;
}

int main()
{
	int a = 0, b = 1;
	swap(&a, &b);
	
	double c = 1.1, d = 2.2;
	swap(&c, &d);
	return 0;
}

感觉那两个地方用的是同一个函数,但实际上不是同一个函数,这只是编译器自动识别。

类型不同:

void swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}

void swap(double* px, double* py)
{
	double tmp = *px;
	*px = *py;
	*py = tmp;
}

个数不同:

void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}

顺序不同:

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;
}

顺序不同指的是形参类型顺序不同。

void f()
{
	cout << "f()" << endl;
}

void f(int a = 0, char b = 1)
{
	cout << "f(int a,char b)" << endl;
}

这俩构成函数重载,但是调用的时候有没有问题?

int main()
{
	f(1);
	f(10,20);

	f();
	return 0;
}

前两个都没有问题,但是第三个就有问题了,“f”对重载函数的调用不明确,存在歧义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马尔科686

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值