并非从0开始的c++ day13

并非从0开始的c++ day13

  • 引用
    • 引用基本用法
    • 引用注意事项
    • 数组的引用
    • 引用的本质
  • const 和#define 区别总结
    • 指针的引用
  • C和C++的区别
    • 引用的使用场景
    • 常量的引用
      • bool类型
    • 内联函数
      • 宏函数的缺陷
      • 什么情况不会成为内联函数
      • 内联函数的好处

引用

引用基本用法

引用是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 区别总结

  1. const 有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查
  2. 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;
}

具体过程:

  1. 在字节常量区找到字符串“翠花”,令指针p指向它
  2. 初始化一个指针&p1,把p赋值给它,经过解引用,p指向的内容将被赋值给p1
  3. 这时输出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++的区别

  1. C语言的结构体不能写函数,C++可以
  2. 结构体定义变量时,C++不需要加struct关键字
  3. 更加严格的类型检查
  4. const修饰的变量,C++有时没有内存,C语言的都有内存
  5. 三目运算符返回的值不一样
  6. 引用和C语言的指针功能一致

引用的使用场景

  1. 引用作为函数参数
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);
}
  1. 引用作为函数的返回值后
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;

什么情况不会成为内联函数

  1. 存在过多的条件判断语句
  2. 函数体过大
  3. 对函数进行取地址操作
  4. 不能存在任何形式的循环语句

内联函数的好处

  1. 有宏函数的效率,没有宏函数的缺点
  2. 类的成员函数默认加上inline
  3. 如果内联函数是成员函数,对象this指针也会被放入合适位置
  4. 类型检查和类型转换、包括在合适位置放入对象this指针这些都是预处理器不能完成的

你可能感兴趣的:(c++,开发语言,算法)