并非从0开始的c++ day13
引用
引用基本用法
引用是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 &pRef ; err
- 引用一旦初始化不能改变它的指向
- 引用必须引用一块合法的内存空间
数组的引用
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;
const 和#define 区别总结
- const 有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查
- const有作用域,而#define不重视作用域,默认定义处到文件结尾。如果定义在指定作用域下有效的常量,那么#define就不能用。
#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;
}
具体过程:
- 在字节常量区找到字符串“翠花”,令指针p指向它
- 初始化一个指针&p1,把p赋值给它,经过解引用,p指向的内容将被赋值给p1
- 这时输出p1,就会输出翠花
//被调函数
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语言的形参指针修改指向内容,在代码上减少了取地址等操作,使代码更简洁易懂
C和C++的区别
- C语言的结构体不能写函数,C++可以
- 结构体定义变量时,C++不需要加struct关键字
- 更加严格的类型检查
- const修饰的变量,C++有时没有内存,C语言的都有内存
- 三目运算符返回的值不一样
- 引用和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;
常量引用注意:
- 字面量不能赋给引用,但是可以赋给const引用
- const修饰的引用不能修改
//普通的引用
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类型
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;
什么情况不会成为内联函数
- 存在过多的条件判断语句
- 函数体过大
- 对函数进行取地址操作
- 不能存在任何形式的循环语句
内联函数的好处
- 有宏函数的效率,没有宏函数的缺点
- 类的成员函数默认加上inline
- 如果内联函数是成员函数,对象this指针也会被放入合适位置
- 类型检查和类型转换、包括在合适位置放入对象this指针这些都是预处理器不能完成的
284



被折叠的 条评论
为什么被折叠?



