引用不是一个新定义的一个变量,而是给已经存在的变量取一个别名,编译器不会给引用变量开辟新的内存空间,而是引用和引用变量共用一个内存空间。下列代码为引用的具体用法:即定义了一个整型变量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,宏不支持类型安全的检查。
1.inline是一种以空间换时间的做法,省去调用函数额开销。所以当代码很长或者有递归的函数不适合使用内联函数。
2.inline对于编译器只是一个建议,编译器会自动优化,如果定义inline的函数很长或者是递归函数时,编译器优化时会自动忽略掉内联。
3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)