#引用与内联函数

#引用与内联函数,第1张

引用与内联函数

  引用不是一个新定义的一个变量,而是给已经存在的变量取一个别名,编译器不会给引用变量开辟新的内存空间,而是引用和引用变量共用一个内存空间。下列代码为引用的具体用法:即定义了一个整型变量a,其中b为a的别名,而c为b的别名。所以可以给别名取别名。需要注意的是0当&在类型和变量名之间时(如int&b)即为引用;当&仅仅出现在变量名之前时即为取地址。

int a = 0;
int& b = a;
int*p = &c
int& d = b;
引用的特性:

  1.引用在定义的时候必须初始化;
  2.一个变量可以有多个引用;
  3.与指针不一样,一旦引用了一个实体后就不能再引用其他实体,而指针可以改变,因为再次引用就会变成赋值。例如:

int a = 0;
int b = 0;
int& c = a;
c = b;//此时不是引用,而是将b的值赋给c

  3.传值比传引用的效率更高,以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者返回值类型时的效率十分低下。

引用的原则:

  1.权限只能缩小或不变,但是不能放大。例如下列三个代码分别是权限不变、权限放大、权限缩小。

//权限不变
int main()
{
	const int a = 0;
    const int& b = a;
	return 0;
}

//权限放大
int main()
{
	const int a = 0;
    int& b = a;
	return 0;
}

//权限缩小
int main()
{
	int a = 0;
    const int& b = a;
	return 0;
}

  2.要想给常量取别名,需要加上const。例如:

int main()
{
    const int& b = 10;
	return 0;
}

再例如:
int main()
{
double d = 2.2;
int f = d;
const int& e = d;
}
  此处之所以是const int& e是因为用int类型给double类型的d取别名时,会取出d的整数部分即2放入一个临时变量中,而这个临时变量具有常量的属性。 f不需要加const是因为是将d的整数部分赋值给f,变量f的改变不会引起临时变量中所存放的常量2的改变。而e需要加const是因为e是常量2的别名而不是d的别名,由于常量不能改变,所以e要加const。

引用的使用场景

  1.作为参数,例如:

void swap(int& x, int& y)
{
	int temp = x;
	x = y;
	y = temp;
}

作为输出型参数时,减少拷贝,提高效率。
  2.作为返回值,以下面这段代码为例,普通的传值返回需要拷贝,而引用返回不需要拷贝。

#传值返回是将返回值n进行拷贝,再传给ret。
int count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
    int ret =  0;
    return 0;
}
#引用返回则不需要拷贝
int count()
{
	static int n = 0;
	n++;
	return n;
}

  可以采用下面这种方式进行验证:

int count()
{
	int n = 0;
	return n;
}
int main()
{
	int ret = count();
	int& ret = count();//此处没法进行编译
	const int& ret = count();//加上const就可以编译
	return 0;
}

如果将int count()改为int& count()

int& count()
{
	int n = 0;
	cout << "n的地址为:" << &n << endl;
	return n;
}
int main()
{
	int& ret = count();
	cout << "ret的地址为:" << &ret << endl;
	return 0;
}

  int& count()是指将n的别名进行返回,同时ret作为count()的返回值的别名的别名,其地址与n的地址相同。所以将引用作为返回值可以不进行拷贝。
注意:函数返回时,出了函数作用域,如果返回对象还在,那么就采用引用返回(例如函数中定义的返回值是static);如果返回对象已经还给系统了,则必须用传值返回,否则就会出现越界问题。
  引用的实例代码如下,当c为静态变量时,因为静态变量只初始化一次,其结果为3;不是静态变量时其输出结果为7。

#include
using namespace std;
int& Add(int a, int b)
{
	static int c = a + b;
	//int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "ret =" << ret << endl;
	return 0;
}

引用和指针的不同点:
  1.引用概念上定义了一个变量的别名,指针储存了一个变量的地址。
  2.引用在定义时必须初始化,指针没有要求。
  3.引用在初始化时引用了一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型的实体。
  4.没有NULL引用,但有NULL指针。
  5.在sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位是4个字节,64位是8个字节)。
  6.引用自加即引用的实体增加1,而指针自加1是指针向后偏移一个类型的大小。
  7.有多级指针,但是没有多级引用。
  8.访问实体方式不同,指针需要显示解引用,引用则是编译器自己处理。
  9.引用比指针使用起来相对更安全。

内联函数

  以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。在函数前增加心理呢关键字将其改成内联函数,在编译期间编译器会用函数体代替函数调用。
  使用方式如下

inline int Add(int x, int y)
{
    return x + y;
}

  c++之所以要创造内联函数主要是为了代替宏的部分作用。1.宏晦涩难懂,容易写错,比如下面的ADD函数中的x和y就必须用多重括号括起来。如下列代码

#define ADD(x,y) ((x)+(y)) 

  2.宏不支持调试。(内联函数在debug版本下可以会展开,需要在常规→优化后可以进行调试)
3,宏不支持类型安全的检查。

inline的特性

  1.inline是一种以空间换时间的做法,省去调用函数额开销。所以当代码很长或者有递归的函数不适合使用内联函数。
  2.inline对于编译器只是一个建议,编译器会自动优化,如果定义inline的函数很长或者是递归函数时,编译器优化时会自动忽略掉内联。
  3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1295572.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存