新C++(1):命名空间\函数重载\引用\内联函数

 "你一无所有地闯荡"

C++的出现,更多的是为了弥补C语言的不足。因此,很多C++的语法既支持C,也会在C中无法解决的问题,提供了自己解决的方法。 

---------前言

(一)命名空间

在一些代码工程量大的项目中,肯定不是单独由一个人完成的。这么多人使用成百上千的代码量,难免会出现自己定义的 变量名、函数......命名相同的情况。

因此,为了解决这样的“命名冲突”的问题(或名字污染),提出了"namespace"关键字。 

 (1)命名域的使用

①普通使用: 

 因此与命名空间配合出现了一个操作符(域名操作符):"::"。

②命名空间嵌套使用(当然这很少):

③使用using 展开命名域

(2)如何理解命名域和作用域

我们知道,一个变量的作用域 其实是决定了它的生命周期的长短。

那么处于命名空间里的变量,是定义在哪里的呢? 其作用域是多大,生命周期是多长呢?

可以看出,全局变量 和 命名空间内变量的地址,是远远低于 在栈上开辟空间的b。

因此,在命名空间里定义的变量,它的存储位置是在全局区。 那么它的生命周期 是随进程的。

(3)如何理解using namespace std? 

可能很多小伙伴,才初始C++的时候,总会看到"using namespace std"的字样,但是说到底,仍然不知道为什么要在main函数前 加这一句。

其实本质上,std是C++库函数的一个命名空间,里面封装了很多函数接口。 

 这也就是为什么使用C++库函数的时候,要使用 域名访问操作符“::”。

而我们也知道 using namespace + 域名其实就是把命名空间里的 变量、函数对外展开,也就是捅破了命名空间(std),对C++库中函数的包裹。

但在实际中,很少会把std标准库里的内容展开。

其根本原因是,难免会造成域外 定义的变量、函数 会和域内定义的命名冲突。
 

根据就近原则,会优先在局部域内找到定义的  rand。 

如果此时全局域出现一个rand,而又包含了含有rand的函数库 

 从而造成二义性的问题。

①半开放式的命名空间展开(using + 命名空间 + 变量、函数) 

因此为了解决这样的问题,也就有了第三种处理这种问题的方式。


(二)函数重载 

 在C中,如果我们要写一个加法,但是是适用多种类型的。

 同样是求两个数的和,功能完全一样,但是却要用不同的函数名进行区别,从函数的可读性来说,也不便于。

(1)什么是函数重载

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

C++引入“函数重载”后,从上层使用的角度上来看,调用的是同一个函数。但事实上,底层根据制定的规则,会去自动调用不同 的函数。 

 达成函数重载的三种情况

①参数类型不同

②参数个数

③参数顺序

(2)函数重载的原理 

可能你会疑问,为什么函数重载C++支持,而C语言不支持呢? 函数名修饰规则的不同

 

可以看出在同一个函数Add下,C语言 下的函数名很简单。但是在C++下对函数修饰的规则做了进一步的修正。

通过这里我们就可以理解了。因为C语言没有函数名修饰规则,也就无法区别同名函数。而C++引入了这一套规则,凭借“参数”(类型、个数、参数顺序)的不同修饰函数名,也就支持了重载。填入符号表,也就便于链接处找到对应的函数调用。

函数重载 == 编译成功?

  

但函数在调用时,会出现问题!

 

其原因就是 函数调用出现了二义性,导致调用函数位置处指名不明确。 

 


(三)引用 

什么是引用呢?

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

(1)如何使用引用? 

①引用语法 

形如如上,就是一个变量的引用。可以显然的看到,引用就是一个数的别名。它就是这个数 

②引用特性

 定义时必须初始化;

 一个变量可以有多个引用;

 引用一旦引用一个实体,再不能引用其他实体;

 ③引用与const 

 

 ④引用的参数与返回值

当用C语言写Swap交换函数时,是用的指针。但C++引入引用后,完全可以替代。 

引用还可以作为参数返回。

int& func()
{
	static int a = 3;
	return a;
}

看看下面代码,如果引用返回会有什么结果?

int& Add(int x, int y)
{
	int c = x + y;
	return c;
}


int main()
{
	int& ret = Add(3, 4);
	cout << ret << endl;
    return 0;
}

 因此为了避免这样的 引用乱用的情况。 

 如果返回值 在出了函数作用域仍然存在,那么此时可以进行引用返回。

 否则,一定不行(仅仅是在此时此刻这么认为!!!)。

(2)引用与指针 

根本上,引用的出现,就是为了 简化C语言的指针。因为其实在太灵活和复杂。

虽然本质上,引用在底层上就是由指针实现的。但在语法层面上,两者应当区别开来。 

①指针与引用的区别 

1.在概念上引用是一个变量的别名,指针存储的是一个地址。

2.引用在定义时必须初始化,指针可以为空。

3.引用只能引用一个实体,指针任何时候可以指向不同实体。

4.sizeof(引用) 数据类型大小,sizeof(指针) 地址空间大小。

5.++ -- 的不同。引用数值变化,指针地址变化。

 

(3)引用的反思 

 引用语法的引入是很成功的。

 单从引用作为参数返回、传入时,减少了非必要的拷贝,大大提高了运行时效率。

 与指针想比,其使用起来简单,没有指针那么复杂,且相对安全。

注:本段所讲的引用,均为 “左值引用!!!”


(四)内联函数 

什么是内联函数?

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

从内联函数的概念上来说,轻而易举知道,该函数就是为了避免 当一个函数频繁调用时,减少建立栈帧的开销。 

(1)宏函数 和 内联函数

 内联函数的功能,就是在执行到调用函数处,不再为之开辟栈帧,而是直接将函数内的代码就地进行展开。

看到如此的使用形式,不禁想起C中也有一种同等类似 形式的函数。-------宏函数

我们知道宏函数的本质,就是文本替换,在预处理的时候 就会在标志处进行文本替换。

那么宏函数有什么缺点呢? 

1.没有严格类型检查,你传double进去 也给你相加

2.无法调试

3.易错 

为什么易错? 

 因此内联函数的出现,恰恰就是为了弥补 宏函数的缺点!

debug版本下可以进入调试

(2)内联函数的特性

inline函数 是一种 以空间 换时间的做法。

缺陷:让可执行程序(obj目标文件)变大

优点:提高程序的运行效率

①编译器决定是否内联展开 

但对于编译器而言,是否选择内联由编译器决定。正如初始C时,将常用变量存入寄存器中一样。

当内联函数足够长时,就算标明了内联属性,但编译器仍然会把它当成普通函数处理。建立栈帧。 

 

如何理解不建议内联函数 定义、声明分离! 

 

本质在于,设置为内联的函数,不会被添加进符号表。

那么当链接时,拿着函数名找不到对于的函数地址! 


总结

①命名空间存在的意义在于,避免“命名冲突”。

②库函数的三种用法:std::+函数名 \ using std::+函数 \ using namespace std;

③函数重载在C++中支持的根本,是引入了函数名修饰规则。

④重载特性:参数类型不同 ||个数不同 || 顺序不同

⑤引用就是一个变量的别名。

⑥引用与指针的区别、引用作为参数、返回值、引用与const。

⑦内联函数与宏函数区别

⑧内联函数的特点。


本篇到此结束

感谢您的阅读~

祝你好运 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值