文章目录
1 引用
1.1 引用的基本概念
#include <stdio.h>
#include "iostream"
using namespace std;
int main()
{
int a = 10;
int *p = &a;
*p = 20;
cout << "a = " << a << endl;
//1 &符号前面有数据类型时,才表示引用,不带数据类型的皆为取地址
int &b = a; //b可以理解为a的别名
b = 40;
//2 c++提供了一种对变量间接操作的方式 ----> 引用
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "&a = " << &a << endl;
cout << "&b = " << &b << endl;
//3 引用一定要初始化 否则报错 Error: Declaration of reference variable 'c' requires an initializer
//int &c;
//4 可对引用再次引用
int &d = b;
cout << "&d = " << &d << endl;
cout << "d = " << d << endl;
return 0;
}
打印结果
a = 20
a = 40
b = 40
&a = 0x7ffeefbff528
&b = 0x7ffeefbff528
&d = 0x7ffeefbff528
d = 40
1.2 引用作为函数参数
#include <iostream>
using namespace std;
struct Teacher{
int id;
char name[64];
};
//1 局部临时变量,会发生值拷贝 并不会改变函数的参数值
void printT1(Teacher t){
cout << "id = " << t.id << endl;
cout << "name = " << t.name << endl;
t.id = 100;
}
//2 通过指针间接修改变量的值
void printT2(Teacher *t){
cout << "id = " << t->id << endl;
cout << "name = " << t->name << endl;
t->id = 100;
}
//3 通过引用来间接修改变量的值
void printT3(Teacher &t){
cout << "id = " << t.id << endl;
cout << "name = " << t.name << endl;
t.id = 1000;
}
void swap1(int a, int b){
int temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void swap3(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
int main(void){
Teacher t1 = {1, "张三"};
printT1(t1);
cout << t1.id << endl;
printT2(&t1);
cout << t1.id << endl;
printT3(t1);
cout << t1.id << endl;
int a = 10;
int b = 20;
swap1(a, b);
cout << "a = " << a << " b = " << b << endl;
swap2(&a, &b);
cout << "a = " << a << " b = " << b << endl;
swap3(a, b);
cout << "a = " << a << " b = " << b << endl;
return 0;
}
打印结果
id = 1
name = 张三
1
id = 1
name = 张三
100
id = 100
name = 张三
1000
a = 10 b = 20
a = 20 b = 10
a = 10 b = 20
1.3 引用的本质
#include <iostream>
using namespace std;
struct Teacher{
int id;
char name[64];
};
struct TypeA{
int *a;
};
struct TypeB{
double &a;
};
//用于说明指针的引用都是占用8个字节
void reSize(){
cout << "sizeof(TypeA) = " << sizeof(TypeA) << endl;
cout << "sizeof(TypeB) = " << sizeof(TypeB) << endl;
}
//用于说明引用相当于常指针
void modifyA(int * const a){
*a = 100;
}
void modifyB(int &a){
//a实际上是一个常量指针,这里给a赋值,编译器会有一个隐形的操作 *
a = 1000;
}
void test(){
int value = 20;
Teacher t1 = {1, "张三"};
modifyA(&value);
cout << "value = " << value << endl;
modifyB(value);
cout << "value = " << value << endl;
}
int main(void){
int a = 10;
int b = 20;
const int c = 10;
//c = 20;//Error:Cannot assign to variable 'c' with const-qualified type 'const int'
//1 引用必须初始化 (由此猜想引用可能是常量)
int &re = a;
//2 不管引用是什么类型,都是8个字节。和指针的大小一样 (由此猜想引用可能是指针类型)
reSize();
//示例引用和常指针对比
test();
//3 总结:
//引用原理: 可以将引用理解为常量指针
//理解引用: 可以将引用理解为变量的别名
return 0;
}
打印结果
sizeof(TypeA) = 8
sizeof(TypeB) = 8
value = 100
value = 1000
1.4 引用作为函数返回值
#include <iostream>
using namespace std;
int getA1(){
int a = 10;
return a;
}
int& getA2(){
int a = 20;
return a;
}
int &getB(){
static int b = 100;
return b;
}
int main(void){
int a = 0;
a = getA1();
cout << "a = " << a << endl;
a = getA2();
cout << "a = " << a << endl;
//1 当函数返回值是一个局部变量的引用的时候,不能再用引用来接收
int &r_a = getA2();//禁止用引用来接收 没有值拷贝动作
cout << "r_a = " << r_a << endl;
//2 当函数返回值是一个静态变量的引用时,可以用引用来接收
int &r_b = getB();
cout << "r_b = " << r_b << endl;
//3 此时r_b 就是getB()方法中b的别名
r_b = 2000;
int b = getB();
cout << "b = " << b << endl;
//4 当引用作为函数的返回值时,只要这个引用是合法的,就可以当左值
getB() = 3000;
return 0;
}
打印结果
a = 10
a = 20
r_a = 32767
r_b = 100
b = 2000
1.5 指针引用
#include <iostream>
using namespace std;
struct Teacher{
int id;
char name[64];
};
int getTeacher_01(Teacher **pp){
Teacher *p = NULL;
p = (Teacher *)malloc(sizeof(Teacher));
if(p == NULL){
cout << "error p == NULL" << endl;
}
memset(p, 0, sizeof(Teacher));
p->id = 30;
*pp = p;
return 0;
}
int getTeacher02(Teacher* &tr){
tr = (Teacher *) malloc(sizeof(Teacher));
if(tr == NULL){
cout << "error tr = NULL" << endl;
return -1;
}
tr->id = 40;
strcpy(tr->name, "张三");
return 0;
}
void freeTeacher_01(Teacher* &tr){
if(tr != NULL){
free(tr);
tr = NULL;
}
}
void freeTeacher_02(Teacher **pp){
if(pp == NULL){
return;
}
Teacher *p = *pp;
if(p != NULL){
free(p);
*pp = NULL;
}
}
int main(void){
Teacher *tp = NULL;
//1 通过二级指针给一级指针赋值
getTeacher_01(&tp);
cout << "tp = " << tp << endl;
cout << "tp->id = " << tp->id << endl;
//2 通过指针引用给指针赋值
getTeacher02(tp);
cout << "tp->name = " << tp->name << endl;
//3 两种释放方式都可以
//freeTeacher_01(tp);
freeTeacher_02(&tp);
cout << "tp = " << tp << endl;
return 0;
}
打印结果
tp = 0x100505420
tp->id = 30
tp->name = 张三
tp = 0x0
1.6 const引用
#include <iostream>
using namespace std;
void printX(const int &re){
cout << " re = " << re << endl;
}
int main(void){
//1 如果被引用的是const常量,必须用const引用来接收
const int a = 10;
const int &b = a;
//int& re_2 = 10;//error:Non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
//2 引用字面量必须加const关键字,这是因为字面量本身没有地址,所以引用无法对字面量取地址
const int& re_2 = 10;
cout << "re_2 = " << re_2 << endl;
return 0;
}
打印结果
re_2 = 10
2 内联函数
#include <iostream>
using namespace std;
inline int func(int a, int b){
return (a < b ? a : b);
}
#define MAX_VALUE(a, b) ((a) < (b) ? (a) : (b))
inline void printValue(int a, int b);
int main(){
//1 调用内联函数的时候,和普通函数的区别是没有函数压栈和出栈的开销
int value = func(10, 20);
cout << "value = " << value << endl;
//inline函数会将func全部展开
// {
// return (a < b ? a : b);
// }
//2 内联函数和宏函数的区别
//内联函数:所有的编译器词法分析和校验都有,是编译器处理的
//宏函数: 由预处理器处理,没有像函数一样的校验
int a = 50;
int b = 20;
int c = MAX_VALUE(a, b);
cout << "c = " << c << endl;
//3 如果函数声明用了inline关键字,但是函数定义没有写inline,编译器仍然不会按inline函数处理
printValue(a, b);
//4 适用场景:函数体很小,且被频繁的调用
return 0;
}
void printValue(int a, int b){
cout << "a = " << a << ", b = " << b << endl;
}
打印结果
value = 10
c = 20
a = 50, b = 20
3 默认参数和占位参数
//2 默认参数必须是从右向左设置,一旦有了默认参数,则右边的参数都必须有默认值
//error:Missing default argument on parameter 'high'
//int volume(int len, int width = 20, int high){
int volume(int len, int width = 20, int high = 30){
return len * width * high;
}
int main(){
int x = 10;
//1 第二个参数是默认参数,可传可不传
func(x);
func(x, 20);
return 0;
}
打印结果
func = 10,a = 100
func = 10,a = 20
4 函数重载
4.1 重载规则
#include <iostream>
using namespace std;
void func(int a){
cout << "func(int a)" << endl;
}
//重载1:方法名相同,参数类型不同
void func(char a){
cout << "func(char a)" << endl;
}
//重载2: 方法名相同,参数个数不同
void func(int a, char b){
cout << "func(int a, char b)" << endl;
}
//重载2:方法名相同,参数类型顺序不同
void func(char a, int b){
cout << "func(int a, char b)" << endl;
}
//重载错误: 返回值不同不能构成重载
//error:Functions that differ only in their return type cannot be overloaded
//int func(char a, int b){
// cout << "func(int a, char b)" << endl;
//}
int main(void){
//1 测试函数重载规则
func(10);
func(10,'a');
func('a', 10);
return 0;
}
执行结果
func(int a)
func(int a, char b)
func(int a, char b)
4.2 重载底层实现
//1 底层实现对应的方法名为function_c
void method(char a){
cout << "function(char a)" << endl;
}
//2 底层实现对应的方法名为function_ci
void method(char a, int b){
cout << "function(char a, int b)" << endl;
}
int main(void){
//2 重载底层实现 (void int short long double char) ---> visldc
method('a');
method('a', 10);
return 0;
}
执行结果
function(char a)
function(char a, int b)
4.3 函数重载与函数默认参数
#include <iostream>
using namespace std;
void func(int a){
cout << "func(int a)" << endl;
}
void func(int a, int b = 0){
cout << "func(int a, int b = 0)" << endl;
}
int main(void){
//1 存在二义性,编译不通过
//func(10); //Error:Call to 'func' is ambiguous
return 0;
}
4.4 函数重载和函数指针
#include <iostream>
using namespace std;
void func(int a, int b){
cout << "a = " << a << ", b = " << b << endl;
}
//声明一个函数类型,返回值为void, 参数列表为int, int
typedef void(functype)(int, int);
//声明一个函数指针类型,返回值为void, 参数列表为int, int
typedef void(*functype_pointer)(int, int);
int main(void){
//1 定义一个函数指针方式1
functype *fp1 = NULL;
fp1 = func;
fp1(10, 20);
//2 定义一个函数指针方式2
functype_pointer fp2 = NULL;
fp2 = func;
fp2(10, 20);
//3 定义一个函数指针方式3
void(*fp3)(int, int) = NULL;
fp3 = func;
fp3(10, 20);
//4 定义一个函数指针方式4
void(*fp4)(int, int) = func;
fp4(10, 20);
return 0;
}
执行结果
a = 10, b = 20
a = 10, b = 20
a = 10, b = 20
a = 10, b = 20