游戏开发之C++引用(C++基础)

Posted 该从何说起呢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏开发之C++引用(C++基础)相关的知识,希望对你有一定的参考价值。

游戏开发之C++引用(C++基础)

C++引用知识大部分知识点来源地【点击跳转】

一、引用的基础概念

  引用是C++对C的重要扩展。用于对指针的安全使用。引用就是一个变量的别名(小名),可以采用不同的变量名,控制同一片内存空间。

语法:数据类型 &变量名 = 变量名;

注意点:

  1. 引用在声明的时候务必要初始化(一个引用可以作为另一个新引用的初始化)。
	int a2 = 200;
	int &b2 = a2;
	int &b3 = b2;
	b2 = 500;
	TestFunc(100);
	printf("%d\\n", a2);
	printf("%d\\n", b2);
	printf("%d\\n", b3);
	printf("%x\\n", &a2);
	printf("%x\\n", &b2);
	printf("%x\\n", &b3);
  1. 引用的&不是取地址运算符,而是起标记作用。
  2. 引用的类型必须和其所绑定的变量的类型相同。
  3. 引用相当于变量或对象的别名,因此不能将已有的引用作为其它变量或对象的名字或别名。
  4. 引用的本质在c++内部实现是一个指针常量。值可以改,指向不能更改。
	数据类型 * const ref = &value;
  1. 引用不是定义一个新的变量或对象,因此内存不会为引用开辟新的空间存储这个引用。
  2. 指针和引用是完全不同的概念,引用和指向的变量拥有相同的内存地址,而指针存储了变量的地址,它自己也拥有自己的内存地址。
  3. 对数组的引用
	int a[3] = { 1,2,3 };
	int(&b)[3] = a;
	std::cout << a[0] << " " << b[0] << " " << &a[0] << " " << &b[0] << std::endl;
	std::cout << a[1] << " " << b[1] << " " << &a[1] << " " << &b[1] << std::endl;
	std::cout << a[2] << " " << b[2] << " " << &a[2] << " " << &b[2] << std::endl;
  1. 对指针的引用
	int a1 = 5;
	int *p = &a1;
	int* &p1 = p;
	std::cout << &p1 << " " << &p << std::endl;
	std::cout << *p1 << " " << *p << std::endl;

二、引用的应用

1.引用作为函数的参数

语法:数据类型 函数名(数据类型&,数据类型&,…);
TIPS:在C++中所有的函数形参尽可能都用引用代替址传递和址传递,因为不管是址传递还是址传递都会在栈区申请临时的空间用于保存址传递的指针和址传递的变量,而引用则不会。

注意点:

  1. 函数中使用引用,可以快速方便的修改,传递参数的值并返回且不需要传递指针,减少编码错误。
  2. 使用引用来作为函数的形参时,形参为传递给函数的实参变量或对象的别名,故系统不会耗费时间在内存上开辟空间来存储形参。
  3. 使用指针作为函数的形参虽然可以达到同样的效果,但当调用函数时仍然需要为形参在栈区开辟无符号整型的四字节空间用于存储形参,而引用不需要。
  4. 如果在编程过程中,既希望通过引用作为函数的参数来提高函数执行效率,又希望保护传递的参数使其在函数中不被改变,则此时应用使用常量的引用来对函数的形参进行约束
  5. 数组的引用作为函数的参数:C++的数组类型是带有长度信息的,引用传递时如果指明的是数组则必须指定数组的长度

2.常量的引用(常引用)

语法:const 数据类型 &变量名(别名) = 变量名;

注意点:

  1. 不可以修改原始的数据,只读。
  2. 变量名可以是常量。如果形参不是常量引用则实参必须是变量。

3.引用作为函数的返回值

语法:类型 &函数名(形参表){函数体}

注意点:

  1. 引用作为函数的返回值时,必须在定义函数时在函数名前加&。
  2. 优点:用引用作为函数的返回值时,最大好处就是在内存中不会产生返回值的副本。
  3. 当函数的返回值(值方式返回)用于初始化一个引用时,有些编译器可以编译通过,有些不可以编译通过。

原因是以值方式返回,C++会创建一个临时变量将返回值拷贝给该临时变量。返回主函数时,临时变量消亡,所以该引用面临无效的危险,很有可能以后的值是个无法确定的值。

  1. 可以用函数的返回的引用作为新引用的初始值,但是前提是该函数返回的引用不是一个局部变量,而是一个全局变量才有意义。
  2. 如果真的希望用函数的返回值(引用)来初始化一个引用,应当先创建一个变量,将函数的返回值(引用)赋给这个变量,然后再用该变量初始化引用。
  3. 函数内部尽量不要返回通过new分配的内存的引用,因为在函数内部保存new出来的对象是一个局部变量,并没有将其赋给一个实际的变量(全局变量),那么当函数执行完可能会出现所指的空间无法释放的问题,从而造成内存泄露。
float fn1(float r)
{
	float temp = r * r*3.14;
	return temp;
}

const float &fn2(float r)
{
	float temp = r * r*3.14;
	printf("temp:%x\\n", &temp);
	return temp;
}

int main()
{
	float a3 = fn1(5.0);
	float a4 = fn2(5.0);
	const float &a5 = fn2(5.0);//返回常引用,避免无意识的错误修改
	printf("%f\\n", a3);
	printf("%f %x\\n", a4, &a4);
	printf("%f %x\\n", a5, &a5);
	return 0;
}

  1. 当返回类成员的引用时候,最好返回常引用,这样可以避免无意识的情况下破坏该类的成员。
  2. 可以用函数返回的引用作为赋值表达式的左值。
int value[10];//全局变量
int error = -1;//全局变量
int &TestValue(int index)
{
	if (index >= 0 && index <= 9)
	{
		return value[index];
	}
	else
		return error;
}

int main()
{
	TestValue(0) = 10;
	TestValue(4) = 12;
	printf("%d\\n", value[0]);
	printf("%d\\n", value[4]);
	return 0;
}

三、总结

  1. 在引用的使用过程中,单纯的给某个变量取别名是毫无意义的,引用的目的主要用于在函数参数的传递过程中,解决大块数据或对象的传递效率和空间不如意的问题。
  2. 用引用传递函数的参数时,能保证参数在传递过程中不产生副本,从而提高效率。同时通过const的使用,可以限制参数在传递过程中的安全性(包括传入和传出)。
  3. 引用本身是目标变量或这对象的别名,对引用的操作本质上就是对目标变量或对象的操作。因此能使用引用时尽量使用引用而非指针。

以上是关于游戏开发之C++引用(C++基础)的主要内容,如果未能解决你的问题,请参考以下文章

Part 1:基础语言-Cocos2d-x手机游戏开发之C++语言基础-关东升-专题视频课程

Visual C++游戏开发笔记之十一 基础动画显示 排序贴图

Visual C++游戏开发笔记之十一 基础动画显示 排序贴图

C++基础学习笔记C++语法之引用

C++基础学习笔记C++语法之引用

C++关于游戏开发的书籍