引用是C++对C的重要扩展。在C/C++中指针的作用基本都是一样的,但是C++增加了另外一种给函数传递地址的途径,这就是按引用传递,它也存在于其他一些编程语言中,并不是C++的发明
引用和C语言的指针一样的功能,并且使语法更加简洁
void test01()
{
int a = 10;
int& b = a;//给变量a取别名b
b = 100;
cout << a << endl;
}
作为形参时可以这样用
void func(int& a)
{
a = 200;
}
void test02()
{
int a = 10;
func(a);
cout << a << endl;
}
int arr[] = { 1,2,3,4,5 };
//第一种方法
//1. 定义数组类型
typedef int(MY_ARR)[5];//数组类型
//2.建立引用
MY_ARR& arref = arr;//建立引用,int &b = a;
//第二种方法
//直接定义引用
int(&arref2)[5] = arr;//int &b = a;
//第三种方法
typedef int(&MY_ARR3)[5];//建立引用数据类型
MY_ARR3 arref3 = arr;
一般最常用第二种方法,其次第一种方法
访问可以用以下方法
for (int i = 0; i < 5; i++)
{
cout << arref[i] << endl;
}
cout << endl;
for (int i = 0; i < 5; i++)
{
arref2[i] = 100 + i;
cout << arref2[i] << endl;
}
引用的本质在C++内部实现是一个常指针
Type& ref = val;//Type* const ref = &val ;
C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见
int a = 10;
int& aRef = a;//自动转换为int* const aRef = &a;
aRef = 20;//内部发现aRef是引用,自动帮我们转换为:*aRef = 20;
#define MA 128
const short ma = 128;
void func(short int a)
{
cout << "func(short int a)" << endl;
}
void func(int a)
{
cout << "func(int a)" << endl;
}
输入参数为ma时,可以检查数据类型
void test01()
{
const char* p = "翠花";
const char*& p1 = p;
cout << p1 << endl;
}
具体过程:
//被调函数
void func(char *& temp)
{
char* p;
p = (char*)malloc(64);
memset(p, 0, 64);
strcpy(p, "小花");
temp = p; //省了*
}
//主调函数
void test02()
{
char* mp = NULL;
func(mp);//省了&
cout << mp << endl;
}
同理,使用引用在栈区上直接将上述p指向的值赋值给temp(mp),使输出时,输出了想要的结果
对比c语言的形参指针修改指向内容,在代码上减少了取地址等操作,使代码更简洁易懂
void func(int& a, int& b)
{
int sum = a + b;
cout << "sum=" << sum << endl;
}
void test01()
{
int a = 10;
int b = 20;
func(a, b);
}
int& func2()
{
int b = 10;//不要返回局部变量的引用
int& p = b;
return p;
}
int& func3()
{
static int b = 10;
return b;
}
void test02()
{
int& q = func2();
q = 100;
cout << q << endl;
func2() = 200;
cout << q << endl;
cout << "func2()=" << func2() << endl;
func3() = 100;
cout << "func3()=" << func3() << endl;
}
在fun2中,直接访问fun2能得到局部变量b的值,但是通过在主调函数test02中,使用引用q来修改这个值时,可以发现其实是修改不了的,在第3次输出的时候,依然是10,这里应该是个bug,但是vs不会报错,在linux里会报错
在func3中,在声明局部变量b时,使用static关键字修饰,就可以将这个变量变为静态,在编译时分配空间,在外部可以修改
如果要函数当左值,你们该函数必须返回引用
常量引用的定义格式:
const Type& ref = val;
常量引用注意:
//普通的引用
int a = 10;
int& ref = a;
ref = 20;
//int& ret2 = 10; 不能给字面量取别名 err
const int& ref3 = 10;//可以给const修饰的引用赋予字面量
//const修饰符修饰的引用的原理
//编译器会把上面的代码变为:int temp = 10; const int &ref3 = temp;
//ref3 = 200; err
bool类型定义的变量只有两个值,true和false,真和假,1和0
bool is = 1;//注意:is除0以外,都是真
if (is)
{
cout << "真" << endl;
}
else
{
cout << "假" << endl;
}
#define ADD(x,y) x+y
void test()
{
//10 + 20 * 2
int ref = ADD(10, 20) * 2;
cout << "ref = " << ref << endl;
}
宏函数这里不检查语法,直接在调用时替换,所以没有提前考虑括号等符号优先级
在普通函数前面加上inline 是向编译器申请成为内联函数
inline int Add(int x, int y)
{
return x + y;
}
内联函数对比宏函数,速度更快,效率更高
但是inline只是申请成为内联函数,不一定真的成为内联函数,只是加大成为内联函数的概率,同时,如果在代码中调用某一函数过多,该函数有可能成为内联函数,所以内联函数是不可控的,成为内联函数是由编译器来规定的。
int ref2 = Add(10, 20) * 2;
cout << "ref2 = " << ref2 << endl;
输出的结果为60,所以内联函数是检查语法的,并且重视了自己的符号优先级
#define COMAPD(x,y) ((x)<(y)?(x):(y))
void test02()
{
int a = 1;
int b = 4;
cout << "COMAPD(x,y) = " << COMAPD(++a, b) << endl;
}
宏函数缺陷2 ,这里输出时,会先++a后跟b比较,比较a小,所以输出的是++a,于是输出结果为3,并不是1或者2
如果换成内联函数,则输出的结果为2,只会在传入参数时,++一次
inline int func(int x, int y)
{
return x < y ? x : y;
}
cout << "func = " << func(++a, b) << endl;