【C++】命名空间、缺省参数、函数重载、引用

1.认识命名空间

C++总计63个关键字,C语言32个关键字在这里插入图片描述

下面让我们学习一下第一个关键字namespace

首先,我们来看下面的代码
在这里插入图片描述
我们定义了一个名为 rand 的全局变量,此时可以正确的打印出来。

当我们引用了<stdlib.h>这个头文件时,我们发现此时代码就会报错,如下图。
在这里插入图片描述
在这里插入图片描述
我们都知道,rand是一个产生随机数的函数名,此时该名称与我们定义的全局变量命名发生了冲突,编译器就不知道选哪个了。
然而,C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字然后接一对{}即可,{}中即为命名空间的成员。

命名空间有几种使用方式:

  1. 正常的命名空间定义
//aim 是命名空间的名字,实际中一般以项目名称命名
namespace aim1
{
	int rand = 10;
}
  1. 嵌套定义
namespace aim1 //命名空间1
{
	int rand = 10;

	namespace aim2//命名空间2
	{
		int rand = 20;
	}
}
  1. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中

两个文件中的同名命名空间最后会进行合并,因此会出现重定义问题。
在这里插入图片描述

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

2.命名空间的使用

使用命名空间解决访问冲突的问题后,我们发现仍然访问不到它,此时rand使用的依然是rand函数,打印出来函数的地址。
在这里插入图片描述

下面就来介绍一下命名空间是如何访问的,有3种方式:

  1. 命名空间名称作用域限定符

作用域限制符就是两个冒号,此时我们就可以访问到定义的变量了
在这里插入图片描述

  1. 使用using将命名空间中某个成员引入

using是我们学习的第二个关键字
在这里插入图片描述

我们发现,只有被引入的成员才可以被访问,其它成员依旧不可以。若想访问其它成员,也需要将其引入

  1. 使用using namespace 命名空间名称引入

在这里插入图片描述
此时我们发现,a变量可以访问了,然而rand又出现了问题。什么原因呢?

我们知道,编译器的默认查找是:
a. 当前局部域
b. 全局域
b. 到展开的命名空间中查找

此时我们的全局域中和命名空间中都有rand,显然不知道选哪一个,此时我们就需要指定了。因此使用第三种方式时要慎重,不然就是自找麻烦
/
此时我们就可以发现,若某一成员需要经常使用,可以将其引入;对于不常使用的成员,可以使用命名空间加作用域限定符
在这里插入图片描述
很显然,引入了成员后使用更加方便。

自己在学习中遇到的问题:为什么使用命名空间中的宏时不需要指定?
在这里插入图片描述
宏定义是在编译时预处理阶段完成的,而命名空间是在编译时进行名称空间分配和解析的在预处理阶段,编译器并不知道命名空间的存在,所以它无法对命名空间进行解析,因此也就无法指定命名空间。
当使用命名空间内的宏时,编译器会在预处理阶段将宏展开成相应的代码,而展开后的代码中不包含命名空间,因此不需要指定命名空间

3.C++的输入和输出

  • 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std

在这里插入图片描述

  • cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
  • <<流插入运算符,>>流提取运算符。
  • 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型
    浮点数输出时,也不会像scanf 那样默认小数点后6位;它是原样输出。

在这里插入图片描述

  • 输入时,也不需要取地址了

在这里插入图片描述

std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?

  1. 日常练习中,建议直接using namespace std即可,这样就很方便
  2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以在项目开发中建议使用像 std::cout这样使用时指定命名空间 或 using std::cout展开常用的库对象/类型等方式

4.缺省参数

4.1缺省参数的概念

缺省参数是声明定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
在这里插入图片描述

4.2缺省参数的分类

  1. 全缺省参数

在这里插入图片描述
2. 半缺省参数

在这里插入图片描述

注意:

  • 半缺省参数必须从右往左依次来给出,不能间隔着给。

在这里插入图片描述

  • 缺省参数不能在函数声明和定义中同时出现

如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值
在这里插入图片描述

在这里插入图片描述

  • 缺省值必须是常量或者全局变量

5.函数重载

C语言是不支持同名函数存在的,C++支持。

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

  1. 参数类型不同

在这里插入图片描述

  1. 参数类型的顺序不同

在这里插入图片描述

  1. 参数的个数不同

在这里插入图片描述

注意:

  • 同一作用域中,同名函数要想同时存在,必须满足重载的规则。
  • 不同作用域,可以有同名函数
  • 返回值是不构成重载的(返回值不像参数,编译器对它是无法区分的,它也不是必须的)
  • 重载的规则是针对于参数的类型和个数,与参数的名称无关、参数缺省无关

为什么C++支持重载,C语言不支持?

  • 因为在程序进行链接的时候,是使用函数名去找地址的,如果声明和定义分离,C语言是直接使用函数名去找,区分不开。
  • C++使用函数名修饰规则,可以区分。

6.引用

6.1引用的概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间,它们的地址是一样的

定义方式:类型& 引用变量名(对象名) = 引用实体;

在这里插入图片描述

注意:引用类型必须和引用实体是同种类型的

在这里插入图片描述
引用就是祖师爷本贾尼觉得C语言指针不好才搞得,下面的代码就比指针方便的多。

在这里插入图片描述

6.2引用的特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
  1. 引用在定义时必须初始化

在这里插入图片描述

  1. 一个变量可以有多个引用
int main()
{

	int x = 10;
	//一个变量多个引用
	int& a = x;
	int& b = x;
	int& c = x;
	int& d = x;

	return 0;
}
  1. 引用一旦引用一个实体,再不能引用其他实体

下面的代码中是将a变成y的别名?还是将y赋值给a呢?
在这里插入图片描述
很显然,它是将y赋值给了a

6.3常引用(重点题目)

void TestConstRef()
{
	const int a = 10;
	//int& ra = a;   // 该语句编译时会出错,a为常量
	const int& ra = a;

	// int& b = 10;  // 该语句编译时会出错,b为常量
	const int& b = 10;

	double d = 12.34;
	//int& rd = d;  // 该语句编译时会出错,类型不同,d为常量
	const int& rd = d;
}
  1. 权限的平移
int main()
{
	const int m = 0;

	//权限的放大
	//int& n = m; //error  m的权限是可读,n的权限是可读可写的

	//权限的平移
	const int& n = m;//可以
	
	//可以,不是权限的放大
	//只是将m的值拷贝给x,x的修改不影响p
	int x = m;

	return 0;
}
  1. 权限的缩小

在这里插入图片描述

  1. 权限的放大(错误、易错
int main()
{
	const int m = 0;
	//cosnt修饰指针,左定值,右定向
	//p1可以修改,*p1不可以,const修饰的是*p1
	const int* p1 = &m;
	p1++;

	//权限的放大,不可以
	//int* p2 = p1;  //易错

	//权限平移,可以
	const int* p2 = p1;
	return 0;
}

总结:值之间没有权限的放大和缩小的概念,只是一个拷贝;指针与引用有权限放大与缩小的概念,权限只可以缩小,不可以放大

6.4引用和指针的区别

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
在这里插入图片描述

在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{
	int x = 0;
	int& y = x;
	y = 10;
	
	int n = 10;
	int* p = &n;
	*p = 20;
	return 0;
}

我们来看引用和指针的反汇编对比
在这里插入图片描述

引用和指针的不同

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全
  • 51
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
C++中,我们可以使用缺省构造函数来创建一个对象数组。 缺省构造函数是指在定义类时没有显式定义任何构造函数的情况下,默认生成的构造函数。它不带任何参数,并且没有函数体,其作用是为对象提供默认的初始化。 如果我们将一个类定义为数组的元素类型,可以使用缺省构造函数来创建一个对象数组。例如,假设我们有一个名为Person的类,没有任何构造函数的定义。我们可以通过以下方式创建一个Person对象数组: Person arr[5]; 上述代码将创建一个名为arr的Person对象数组,数组中包含了5个Person对象。由于缺省构造函数的存在,每个元素都会被默认初始化为该类的默认值。具体的初始化规则取决于成员变量的类型和定义。如果在Person类中定义了成员变量的默认值,那么每个元素都将被初始化为这些默认值。 如果我们想要自定义初始化每个元素,可以通过重载构造函数的方式来实现。这样,在创建对象数组时,我们也可以传递参数来初始化每个元素。例如,如果我们想要将数组中的每个Person对象的年龄初始化为25岁,可以定义一个带有参数的构造函数,并使用如下方式创建数组: Person arr[5] = { Person(25), Person(25), Person(25), Person(25), Person(25) }; 上述代码将创建一个Person对象数组,其中每个元素的年龄被初始化为25岁。 总结起来,通过使用缺省构造函数,我们可以方便地创建对象数组,并根据需要进行默认初始化或自定义初始化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值