一.引用(别名)
#include<iostream>
using namespace std;
void func(int* p){
*p = 11;
}
void func2(int& q){//引用
cout << "&q:" << &q << endl;//本质上n和q指向同一个地址,只是名字不同
q = 12;
}
int main(){
int n = 10;
cout << n << endl;
func(&n);//容易出现野指针和空指针
cout << n << endl;
cout << "&n:" << &n << endl;
func2(n);//可以避免出现
cout << n << endl;//本质上n和q指向同一个地址,只是名字不同
int& m = n;
cout << "&m:" << &m << endl;//m和n也是指向同一个地址
}
何处使用引用
- 函数参数列表
- 函数返回值
- 成员变量 -- 对象初始化时,必须显示初始化的变量
为何使用引用
- 避免对象复制
- 避免传递空指针
- 使用方便
函数三种传参方式
- 传值
void Func(int n)
- 传地址/指针
void Func(int* n)
- 传引用
void Func(int& n)
引用作用:取代指针
引用与指针的区别
- 指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
- 引用只能在定义时被初始化一次,之后不可变;指针可变;
- 引用不能为空,指针可以为空;
- 引用使用时无需解引用
*
,指针需要解引用; sizeof 引用
得到的是所指向的变量/对象的大小,而sizeof 指针
得到的是指针本身的大小;- 对于引用类型的成员变量,所属类的大小时按照指针大小计算,自身大小按照自身类型计算。
引用通常用于三种情形:成员变量和函数的参数列表以及函数返回值。
二.拷贝/复制构造函数
语法:
类名(const 类名& 形参){
函数体
}
调用:
类名 对象名; // 调用默认构造函数
类名 对象2 = 对象1; // 调用复制构造函数
类名 对象3(对象1); // 调用复制构造函数
例:
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
Test() {}
Test(Test &t) { cout << "Test(Test &t)" << endl; }
Test(Test const &t) { cout << "Test(Test const &t)" << endl; }
};
int main() {
Test t1;
Test t2 = t1;
const Test t3;
Test t4 = t3;
}
输出结果为:Test(Test &t) //对应“Test t2 = t1;”
Test(Test const &t) //对应“Test t4 = t3;”
三.赋值运算符重载函数
语法:
类名& operater=(const 类名& 形参){
// 赋值操作
return *this;
}
Simple& operator=(const Simple& s){
if(this == &s) return *this;
*p = *(p.s);
return *this;
}
拷贝构造函数与赋值操作符的区别
- 拷贝构造函数:当一个已经存在的对象来初始化一个未曾存在的对象
- 赋值操作符:当两个对象都已经存在
总结:
#include <iostream>
using namespace std;
class Simple{
public:
Simple(){
cout << "constructor" << endl;
}
Simple(const Simple& s){
cout << "copy constructor" << endl;
}
Simple& operator=(const Simple& s){
cout << "operator=" << endl;
return *this;
}
~Simple(){
cout << "destructor" << endl;
}
};
void Func(Simple s){
}
int main(){
Simple s;
Simple s1 = s;//拷贝构造函数
Simple s2(s);
Func(s);//引用
s1 = s;//赋值运算符重载函数
s2 = s;
}
四.深拷贝与浅拷贝
- 浅拷贝:只拷贝指针地址
- 深拷贝:重现分配堆内存,拷贝指针指向内容
三大定律(Rule of three / the Law of The Big Three / The Big Three)
如果类中明确定义下列其中一个成员函数,那么必须连同其他二个成员函数编写至类内,即下列三个成员函数缺一不可:
- 析构函数(destructor)
- 复制构造函数(copy constructor)
- 复制赋值运算符(copy assignment operator)
五.禁用函数
当有时不可拷贝时,就将拷贝构造函数写入private中(C++11之前的版本)或者继续写入public中,但后面加 = delete(C++11之后的版本),编译器也不会再自动生成默认拷贝构造函数