C++入门(下)
目录
前言:
一、函数重载
1、形参类型不同
2、参数个数不同
3、参数类型顺序不同
二、引用
1、引用的概念和定义
2、引用的特性
3、引用的使用
三、const的引用
四、指针和引用的区别
拓展知识:
前言:
hello,各位小伙伴们,上期我们了解到了C++的发展史和一些基础知识,今天紧跟小编的步伐将C++入门剩下的内容学完!
一、函数重载
C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调用就表现出了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的。
形参不同具体指三个方面:1、形参类型不同 2、参数个数不同 3、形参类型顺序不同
1、形参类型不同
比如我们做一个加法运算,在函数进行传递参数的时候,我们要注意传递参数的类型:int、double、float等等.....,在C语言中我们需要根据同的变量类型来设计函数,但在C++中我们可以设计成同一个函数名但参数不同这种多态行为即可,我们下面就以加法运算为例。
#include<iostream>
using namespace std;
int Add(int x, int y)
{cout << "x + y = " << x + y << endl;return x + y;
}
double Add(double x, double y)
{cout << "x + y = " << x + y << endl;return x + y;
}
int main()
{Add(2, 3);Add(2.3, 2.4);return 0;
}
在主函数部分我们调用了两次Add函数,但传递的参数类型不同,但系统会自动区分这两个函数来进行计算。
2、参数个数不同
void f()
{cout << " f() " << endl;
}
void f(int a)
{ cout << " f(int a ) " << endl;
}int main()
{f();f(3);return 0;
}
运行结果:
小伙伴们一定要和前面将的函数参数省略参数区分开,例如下面这种情况。
3、参数类型顺序不同
函数传递参数的顺序不同也可认为与第一种情况类似。、
#include<iostream>
using namespace std;
void func(char a, int b)
{cout << "func(char a ,int b )" << endl;
}
void func(int a, char b)
{cout << "func(int a,char b )" << endl;
}
int main()
{func(1, 'a');func('a', 1);return 0;
}
二、引用
1、引用的概念和定义
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
举一个简单的例子:孙悟空有很多别称比如,孙行者,大圣,在八戒嘴里便是猴哥,在妖怪嘴里便是泼猴....。无一例外在西游记里都指的是孙悟空。
#include<iostream>
using namespace std;
int main()
{int a = 10;int& ra = a;int& rb = a;int& rc = a;int& rd = a;cout << "a = " << a << '\t' << "地址:" << &a << endl;cout << "ra = " << ra << '\t' << "地址:" << &ra << endl;cout << "rb = " << rb << '\t' << "地址:" << &rb << endl;cout << "rc = " << rc << '\t' << "地址:" << &rc << endl;cout << "rd = " << rd << '\t' << "地址:" << &rd << endl;return 0;
}
由此可以看出他们指向一块空间,类型& 引用别名 = 引用对象。
2、引用的特性
• 引用在定义时必须初始化
• 一个变量可以有多个引用
• 引用一旦引用一个实体,再不能引用其他实体
#include<iostream>
using namespace std;
int main()
{int a = 10;//引用必须初始化int& ra = a;int b = 20;ra = b;//这里只是将b的值赋给了ra,在C++种一旦引用就不能改变指向cout << "a = " << a << '\t' << "地址:" << &a << endl;cout << "ra = " << ra << '\t' << "地址:" << &ra << endl;cout << "b = " << b << '\t' << "地址:" << &b << endl;return 0;
}
虽然三者的数值是一样的但b是新创建的变量地址与其他二者不同。
3、引用的使用
我们先举一个简单的例子:数据交换
void Swap(int& ra, int& rb)
{int tmp = ra;ra = rb;rb = tmp;
}
int main()
{int x = 2;int y = 3;cout << "交换前:" << x << ' ' << y << endl;Swap(x, y);cout << "交换后:" << x << ' ' << y << endl;return 0;
}
• 引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。
• 引用传参跟指针传参功能是类似的,引用传参相对更方便一些。
• 引用返回值的场景相对比较复杂,我们在这里简单讲了一下场景,还有一些内容后续类和对象章节
中会继续深入讲解。
• 引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++引用定义后不能改变指向,
同时我们可以对之前学过数据结构中的栈使用引用来进行修改:
#include<iostream>
using namespace std;
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST& rs, int n = 4)
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
}
// 栈顶
void STPush(ST& rs, STDataType x)
{assert(ps);// 满了, 扩容if (rs.top == rs.capacity){printf("扩容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}rs.a = tmp;rs.capacity = newcapacity;}rs.a[rs.top] = x;rs.top++;
}
// int STTop(ST& rs)
int& STTop(ST& rs)
{assert(rs.top > 0);return rs.a[rs.top];
}
三、const的引用
可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
• 需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样一些场景下a*3的结果保存在一个临时对象中, int& rd = d 也是类似,在类型转换中会产生临时对象存储中间值,也就是对rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
• 所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。
举例:
#include<iostream>
using namespace std;
int main()
{const int a = 10;// 编译报错:error C2440: “初始化”: 无法从“const int”转换为“int &”// 这里的引用是对a访问权限的放大//int& ra = a;// 这样才可以const int& ra = a;// 编译报错:error C3892: “ra”: 不能给常量赋值//ra++;// 这里的引用是对b访问权限的缩小int b = 20;const int& rb = b;// 编译报错:error C3892: “rb”: 不能给常量赋值//rb++;return 0;
}
#include<iostream>
using namespace std;
int main()
{int a = 10;const int& ra = 30;// 编译报错: “初始化”: 无法从“int”转换为“int &”// int& rb = a * 3;const int& rb = a*3;double d = 12.34;// 编译报错:“初始化”: 无法从“double”转换为“int &”// int& rd = d;const int& rd = d;return 0;
}
四、指针和引用的区别
C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。
• 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。
• 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
• 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
• 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
• sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)
• 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。
拓展知识:
虽然我们在前面验证过引用不会开辟新的空间,但这是在语法层面上的,在汇编角度上来说引用时需要开辟新的空间的,并且引用这个语法的底层时使用C语言的指针来完成的。
int main()
{int a = 10;int& ra = a;int b = 20;int* pb = &b;//在汇编层面没有引用概念,引用在底层是使用指针的构建的return 0;
}
转到汇编角度:
我们发现指针与引用在汇编角度时一样的。
C++入门的介绍就到这里啦,下期我们将会正式进入C++的天地。