
默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。⼀个类,我们不写的情况下编译器会默认生成以下6个默认成员函数。 我们需要从从两方面入手: 第⼀:我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求。 第二:编译器默认生成的函数不满足我们的需求,我们需要自己实现,那么如何自己实现?
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象(局部对象在栈帧创建时,空间就开好了),而是对象实例化时初始化对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数自动调用的特点就完美的替代的了Init。
构造函数有如下特点:
1. 函数名与类型同名
2. 可以重载
3. 没有返回值(不用写void)
4. 如果用户没有显式写构造函数,编译器会生成一个默认的无参构造函数,一旦用户显式定义编译器将不再生成。
// 构造函数
// 1. 函数名和类名同名 2. 可以重载 3. 没有返回值 4. 用户不写编译器会默认生成无参的构造函数
class Date
{
public:
// 无参构造
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
// 带参数构造
Date(size_t year, size_t month, size_t day)
{
_year = year;
_month = month;
_day = day;
}
//// 全缺省构造
//Date(size_t year = 1, size_t month = 1, size_t day = 1)
//{
// _year = year;
// _month = month;
// _day = day;
//}
//
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
size_t _year;
size_t _month;
size_t _day;
};
int main()
{
// 调用带参数的构造
Date d1(2025,7,5);
d1.Print();
//// 无参构造和全缺省构造会产生调用歧义
//Date d2;
//d2.Print();
// 无参的不能这么写 会和函数声明搞混 eg: void func
// 这是函数声明还是函数定义呢?
/*Date d2();
d2.Print();*/
//// 如果注释掉无参的构造和全缺省构造,会报错
//// C2512 没有合适的默认构造函数可用
//Date d2;
//d2.Print();
// 调用无参的构造函数
Date d3;
d3.Print();
return 0;
}默认构造函数分为三类:
using namespace std;
class Time
{
public:
Time()
{
_hour = 1;
_minute = 1;
_second = 1;
}
private:
size_t _hour;
size_t _minute;
size_t _second;
};
class Date
{
public:
// 不写构造函数 编译器会自动生成默认构造函数
// 对于内置类型 编译器是否处理没有明确要求
// 对于自定义类型 调用该类型的默认构造函数
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
size_t _year;
size_t _month;
size_t _day;
Time _t;
};
int main()
{
Date d1;
d1.Print();
return 0;
}
观察调试结果,我们可以得到如下结论: 对于编译器默认生成的构造函数,处理不同类型数据有不同行为:
VS环境,给出随机值Time类的无参构造函数注释掉,会有如下现象:

Time类调用它的默认构造函数,而Time类的默认构造函数是编译器生成的,又是处理内置类型,所以VS不做处理,给出随机值
针对这个问题C++11打了个补丁:内置类型成员变量在声明时给缺省值,用缺省值初始化
using namespace std;
class Time
{
public:
/*Time()
{
_hour = 1;
_minute = 1;
_second = 1;
}*/
private:
// C++11 在声明时给缺省值
size_t _hour = 1;
size_t _minute = 1;
size_t _second = 1;
};
class Date
{
public:
// 不写构造函数 编译器会自动生成默认构造函数
// 对于内置类型 编译器是否处理没有明确要求
// 对于自定义类型 调用该类型的默认构造函数
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// C++11 在声明时给缺省值
size_t _year = 1;
size_t _month = 1;
size_t _day = 1;
Time _t;
};
int main()
{
// 此时 Time类和Date类只有编译器默认生成的构造函数
Date d1;
d1.Print();
return 0;
}![![[Pasted image 20250707095835.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/5c218dbe849cde534493716f778f1087.png)
总结:什么时候要显式定义构造函数?
析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,比如局部对象是存在栈帧的,函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作。析构函数的功能类比我们之前Stack实现的Destroy功能,而像Date没有Destroy,其实就是没有资源需要释放,所以严格说Date是不需要析构函数的
析构函数有如下特点:
1. 函数名和类名相同,在函数名前加~
2. 没有返回值
3. 不能重载,意味着一个类只有一个析构函数
4. 如果用户没有显式写,编译器会默认生成析构函数
5. 对象的生命周期结束,编译器自动调用析构函数
class Stack
{
public:
Stack(size_t n = 4)
{
cout << "Stack(size_t n = 4) 析构" << endl;
_arr = (int*)malloc(sizeof(int) * n);
if (_arr == nullptr)
{
perror("malloc err!");
return;
}
_capacity = n;
_top = 0;
}
~Stack()
{
cout << "~Stack() 析构" << endl;
assert(_arr);
free(_arr);
_arr = nullptr;
_capacity = _top = 0;
}
private:
int* _arr;
int _capacity;
int _top;
};
int main()
{
Stack st1;
return 0;
}和构造函数一样,如果我们不显式实现析构函数,编译器生成的析构函数对于内置类型不做处理,对于定义类型会调用它的析构函数,值得一提的是,是我们显式写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类型成员无论什么情况都会自动调用析构函数
class tmp
{
public:
~tmp()
{
cout << "~tmp() 析构" << endl;
}
private:
int _num;
};
class Stack
{
public:
Stack(size_t n = 4)
{
cout << "Stack(size_t n = 4) 构造" << endl;
_arr = (int*)malloc(sizeof(int) * n);
if (_arr == nullptr)
{
perror("malloc err!");
return;
}
_capacity = n;
_top = 0;
}
/*~Stack()
{
cout << "~Stack() 析构" << endl;
assert(_arr);
free(_arr);
_arr = nullptr;
_capacity = _top = 0;
}*/
private:
int* _arr;
int _capacity;
int _top;
tmp _t;
};
int main()
{
Stack st1;
return 0;
}我们可以通过调试观察:

总结:什么时候需要显式实现析构函数?
Stack List…设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?( )
C c;
int main()
{
A a;
B b;
static D d;
return 0;
}static对象的存在, 因为static改变了对象的生存作用域,需要等待程序结束时才会析构释放对象static c a b dB A D C拷贝构造函数的第一个参数是自身类型的引用,且任何额外的参数都有缺省值,这样的函数叫做拷贝构造函数,用于同类对象的拷贝初始化,是构造函数的重载。 本文以最常规情况的拷贝构造函数展开,即有且仅有一个参数:类类型对象的引用 拷贝构造函数有如下特点:
// 拷贝构造函数
// 构造函数的重载,第一个参数必须是类类型对象的引用
// 用于同类对象的拷贝初始化
class Date
{
public:
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
Date(Date& d)
{
cout << "call Date(Date& d)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
size_t _year;
size_t _month;
size_t _day;
};
int main()
{
Date d1;
// 两种写法都可以
Date d2 = d1;
// d是d1的别名,d3是this指针
Date d3(d1);
d1.Print();
d2.Print();
d3.Print();
return 0;
}再来看一段代码:
Date(Date& d)
{
cout << "call Date(Date& d)" << endl;
// 如果不小心写反了会发生什么?
d._year = _year;
d._month = _month;
d._day = _day;
}其余部分不变

初始的d1也被修改成随机值了,我们进行拷贝构造,提供拷贝值的对象是不能被修改的,所以为了防止这样的情况发生,我们做如下处理:Date(const Date& d)保证d的只读性
// 拷贝构造函数
// 构造函数的重载,第一个参数必须是类类型对象的引用
// 用于同类对象的拷贝初始化
class Date
{
public:
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
Date(const Date& d)
{
cout << "call Date(Date& d)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
size_t _year;
size_t _month;
size_t _day;
};
int main()
{
Date d1;
// 两种写法都可以
Date d2 = d1;
// d是d1的别名,d3是this指针
Date d3(d1);
d1.Print();
d2.Print();
d3.Print();
return 0;
}C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以自定义类型传值传参和传值返回都会调用拷贝构造// 自定义类型对象进行拷贝行为必须调用拷贝构造
// 自定定义类型传值传参和传值返回都会调用拷贝构造完成
class Date
{
public:
Date(size_t year, size_t month, size_t day)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
cout << "调用 Date(const Date& d)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
size_t _year;
size_t _month;
size_t _day;
};
void func(Date d)
{
d.Print();
}
int main()
{
Date d1(2025, 7, 9);
func(d1);
return 0;
}
调试看一下函数行为:
而传指针和传引用可避免拷贝构造:


C++推荐使用传引用的方式,因为引用语义更清晰、不能为 null、更安全也更简洁,适合绝大多数函数参数传递场景,除非参数可以为空或需要修改指针本身,否则优先使用引用传参
为什么传值会引发无穷递归?

// 如果不显式写拷贝构造,编译器会默认生成拷贝构造,
// 自动⽣成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),
// 对自定义类型成员变量会调用它的拷贝构造
class Stack
{
public:
Stack(size_t n = 4)
{
// cout << "Stack(size_t n = 4) 构造" << endl;
_arr = (int*)malloc(sizeof(int) * n);
if (_arr == nullptr)
{
perror("malloc err!");
return;
}
_capacity = n;
_top = 0;
}
void Push(int data)
{
_arr[_top++] = data;
}
~Stack()
{
// cout << "~Stack() 析构" << endl;
assert(_arr);
free(_arr);
_arr = nullptr;
_capacity = _top = 0;
}
private:
int* _arr;
int _capacity;
int _top;
};
int main()
{
Stack st1;
st1.Push(1);
st1.Push(1);
st1.Push(1);
Stack st2 = st1;
return 0;
}
崩溃了

完成了拷贝,程序却崩溃了,为什么?我们没有显式写拷贝构造,默认生成的拷贝构造调用栈对象的拷贝构造,进行了浅拷贝。
![![[Pasted image 20250709174150.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/813739387d8396e382834e4ba10f7ee3.png)
而深拷贝,会复制一个相同的空间,这样就不会冲突
![![[Pasted image 20250709175310.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/0fd4e0ac59f23147278d6b37113ed463.png)
class Stack
{
public:
Stack(size_t n = 4)
{
// cout << "Stack(size_t n = 4) 构造" << endl;
_arr = (int*)malloc(sizeof(int) * n);
if (_arr == nullptr)
{
perror("malloc err!");
return;
}
_capacity = n;
_top = 0;
}
// 深拷贝
// Stack st2 = st1;
Stack(const Stack& st)
{
_arr = (int*)malloc(sizeof(int) * st._capacity);
if (_arr == nullptr)
{
perror("malloc err!");
return;
}
memcpy(_arr, st._arr, sizeof(int)* st._capacity);
_capacity = st._capacity;
_top = st._top;
}
void Push(int data)
{
_arr[_top++] = data;
}
~Stack()
{
// cout << "~Stack() 析构" << endl;
assert(_arr);
free(_arr);
_arr = nullptr;
_capacity = _top = 0;
}
private:
int* _arr;
int _capacity;
int _top;
};
int main()
{
Stack st1;
st1.Push(1);
st1.Push(1);
st1.Push(1);
Stack st2 = st1;
return 0;
}![![[Pasted image 20250709175225.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/0eb19b325140caa4b532df9aef7bddbd.png)
完成深拷贝,二者有自己的独立空间
总结:什么时候需要显式写拷贝构造?
DateStackint main()
{
int num1 = 10;
int num2 = 30;
int mul = num1 * num2;
int plus = num1 + num2;
return 0;
}对于内置类型,使用操作符会调用具体的指令

而对于自定义类型,我们需要使用函数自己控制运算符的作用,这里就引入了运算符重载,格式如下:
返回类型 operator操作符(参数列表),这就是函数,只不过函数名是operator操作符
运算符重载有以下注意事项:
C++不支持@这个符号void operator-(int a, int b)是不行的// 参数类型必须要有一个是类类型
// “operator -”必须至少有一个类类型的形参
void operator-(int a, int b){}![![[Pasted image 20250720145107.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/3b144571790eba8e269a3f7a7d43fedb.png)
.* . sizeof ?: ::
.*这个运算符的场景很少见:// .*不能重载
class A
{
public:
void func()
{
cout << "A::func()" << endl;
}
};
typedef void(A::* PF)(); //成员函数指针类型
int main()
{
// C++规定成员函数要加&才能取到函数指针
PF pf = &A::func;
A obj;//定义ob类对象temp
// 对象调⽤成员函数指针时,使⽤.*运算符
(obj.*pf)();
return 0;
}我们看个案例:
// 自定义类型呢?
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
~Date()
{
_year = -1;
_month = -1;
_day = -1;
}
// private:
int _year;
int _month;
int _day;
};
bool operator>(const Date& d1, const Date& d2)
{
if (d1._year > d2._year)
{
if (d1._month > d2._month)
{
if (d1._day > d2._day)
{
return true;
}
}
}
else
{
return false;
}
}
int main()
{
Date d1(2025, 7, 17);
Date d2(2025, 7, 20);
// 转换成调用 operator>(d1, d2)
cout << (d1 > d2) << endl;
// 可以显式调用
cout << operator>(d1, d2) << endl;
return 0;
}不推荐显式调用,因为这样就突出不了运算符重载的优势了
![![[Pasted image 20250720145708.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/16afe2921453c2ff64e8c1e31c59c7ca.png)
注意看:private被我注释掉了,此时数据是公开访问的
![![[Pasted image 20250720145837.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/5b1eb26df5bf00ce021248bd8f1e0869.png)
而如果数据被private保护,我们如何重载运算符呢?这里提供三种方法
Get Set函数,Java使用这个方法偏多//eg:
int GetYear()
{
return _year;
}this,要调整参数个数class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
~Date()
{
_year = -1;
_month = -1;
_day = -1;
}
bool operator>(const Date& d2)
{
if (this->_year > d2._year)
{
if (this->_month > d2._month)
{
if (this->_day > d2._day)
{
return true;
}
}
}
else
{
return false;
}
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2025, 7, 17);
Date d2(2025, 7, 20);
// 转换成调用 operator>(d1, d2)
cout << (d1 > d2) << endl;
// 可以显式调用
cout << d1.operator>(d2) << endl;
return 0;
}赋值运算符重载用于一个已经存在的对象拷贝复制给另一个已经存在的对象,这里要和拷贝构造函数区分开。以下是赋值运算符重载的特点:
const 当前类类型引用,否则会传值传参产生拷贝
而对于自定义类型:
class Date
{
public:
// 构造
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
// 拷贝构造
Date(const Date& d)
{
cout << "Date(const Date & d)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值运算符重载
Date& operator=(const Date& d)
{
// 防止自己给自己赋值
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 返回值是Date类
return *this;
}
// 析构
~Date()
{
_year = _month = _day = -1;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2025, 7, 20);
Date d2(2024, 7, 28);
// 拷贝构造
Date d3 = d1;
// 赋值运算符重载
d1 = d2 = d3;
d1.Print();
d2.Print();
d3.Print();
}![![[Pasted image 20250720152705.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/d19b8b828c42aa4743dd993ac6c45caa.png)
如果返回值为空,就会报错:
// 二元“=”: 没有找到接受“void”类型的右操作数的运算符(或没有可接受的转换)`
d1 = d2 = d3;![![[Pasted image 20250720152925.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/3200d47888f3ecf345497aa2490f5b98.png)
我们现在来着重讨论传值返回和传引用返回的区别:
// 传值返回(非优化版本,强制拷贝构造)
Date func()
{
Date d1;
Date d2;
if (time(0) % 2)
{
return d1; // 编译器无法预测 取消RVO优化
}
else
{
return d2;
}
}
int main()
{
const Date& ref = func();
return 0;
}![![[Pasted image 20250720160957.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/b75fe2c05e3ed50cf828a03e9fb76ed7.png)
看一下具体行为(非优化版本):
传值返回
画一个函数栈帧理解一下(优化版本):
┌──────────────────────────────┐
│ main() │
│ ┌──────────────────────────┐ │
│ │ ref = func() │ │
│ │ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ func() │ │ │
│ │ │ ┌───────────────┐ │ │ │
│ │ │ │ Date d; │ │ │ │
│ │ │ │ (构造#1) │ │ │ │
│ │ │ └───────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌───────────────┐ │ │ │
│ │ │ │ return d; │ │ │ │
│ │ │ │ => 拷贝构造#2 │ │ │ │
│ │ │ └───────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ d 析构 (析构#1) │ │ │
│ │ └─────────────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ const Date& ref │ │ │
│ │ │ 绑定返回值的临时 │ │ │
│ │ │ (有时会额外复制) │ │ │
│ │ │ => 析构#2, 析构#3 │ │ │
│ │ └──────────────────────┘ │ │
│ └──────────────────────────┘ │
└──────────────────────────────┘总结:
[func 调用栈]
┌───────────────┐
│ Date d; │ ← 局部变量 d
│ │
│ return d; │ ← 拷贝构造!临时#1
└───────────────┘
│
▼
[main 调用栈]
┌───────────────┐
│ const Date& ref; │ ← 绑定返回值临时
└───────────────┘
析构:
局部 d 析构(离开 func)
返回值临时析构(ref 生命周期结束)
可能还有:
有的编译器生成额外延续临时,也会析构C++ 值返回需要拷贝,RVO 省掉拷贝;const& 会延续临时,多次析构是自然现象。d 析构 1 次(func 结束),return 时临时值析构 1 次,main 里 ref 绑定的延续临时析构 1 次
而使用引用返回会生成d1 d2的别名,减少了拷贝
![![[Pasted image 20250720162717.png]]](https://developer.qcloudimg.com/http-save/yehe-100000/2fa5dd4245877baf86cb5f679be92cfc.png)
ref是tmp,是d1 d2的别名
看一下具体行为:
传引用返回
分析:
+----------------------------+
| main() |
| |
| const Date& ref = func(); |
| (悬空引用) |
+----------------------------+
|
▼
+----------------------------+
| func() |
| |
| +----------------------+ |
| | Date d1; | |
| | (栈上局部变量) | |
| +----------------------+ |
| |
| +----------------------+ |
| | Date d2; | |
| | (栈上局部变量) | |
| +----------------------+ |
| |
| if (...) return d1; |
| else return d2; |
| |
| 【func() 结束】 |
| ├─ d1 析构 |
| ├─ d2 析构 |
+----------------------------+为什么没有拷贝?
func 的返回值是 Date&(引用),不是按值返回。
所以 return d1 / return d2 返回的就是 局部变量本身的别名,不需要拷贝,也就不会走拷贝构造。
为什么会析构两次?
d1 和 d2 都是 func 的局部变量,存在 func 的栈帧里。if 分支随机选择:
return d1; 时,main 拿到 d1 的引用
return d2; 时,main 拿到 d2 的引用
无论你拿到谁的引用,func 一旦返回,d1 和 d2 都会自动析构。
所以 func 结束时: d1 会析构 d2 会析构再加一段代码:
// 传引用返回
Date& func()
{
Date d1;
Date d2;
if (time(0) % 2)
{
return d1; // 编译器无法预测 取消优化
}
else
{
return d2;
}
}
int func1()
{
int a = 1;
int b = 2;
int c = 3;
return a + b + c;
}
int main()
{
Date& ref = func();
ref.Print();
return 0;
}此时输出结果为:

为什么?我们看下函数栈帧
Step 1:
[func 栈帧]
┌───────────────┐
│ Date d1; │
│ Date d2; │
└───────────────┘
Step 2:
return d1/d2 的地址 ----> 被 ref 接住
[main 栈帧]
┌───────────────┐
│ Date& ref ----┼────────┐
└───────────────┘ │
│
▼
指向 func 的局部变量
Step 3:
func 返回后
--> func 栈帧销毁
--> d1/d2 内存仍然是旧的,但悬空
Step 4:
调用 func1()
[func1 栈帧]
┌───────────────┐
│ int a; │
│ int b; │
│ int c; │
└───────────────┘
⬆️⬆️⬆️⬆️⬆️⬆️⬆️⬆️⬆️
这里可能会复用func 原来的栈空间
Step 5:
ref.Print() 访问到的其实是
a,b,c 占用的区域里的数据
===> 输出被覆盖的脏数据C++ 函数如果返回局部变量引用,栈帧销毁后,这个引用就悬空。
如果后面又有新的函数调用分配局部变量,就可能覆盖原来的内存区域。
这会导致引用指向的内容被篡改,输出是垃圾值,属于未定义行为。
总结:
在 C++ 里,传值返回和传引用返回的选择,核心看返回值要不要和原来的对象共享。
如果是局部变量或者新建对象,比如 operator+,就必须传值返回,这样才能把局部结果安全拷贝或者移动出来。
如果是内部状态或者链式调用,比如 operator= 或 vector::operator[],就传引用返回,这样可以直接在原对象上操作,省掉拷贝。
唯一需要注意的是局部变量绝不能传引用返回,不然栈帧一结束,引用就悬空了,行为是未定义的。
另外现代编译器对值返回会做 RVO 优化,很多时候根本不会产生拷贝开销。
const成员函数const修饰的成员函数称作const成员函数,const放到成员函数参数列表的后面const修饰该成员函数的this指针,表明该成员函数不能对类的任何成员进行修改操作,eg:Date* const this变为const Date* const this// const成员函数
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{
// ...
}
// Date* const this -> const Date* const this
void Print()const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// d1可以调用Print 权限的缩小
Date d1(2025, 8, 13);
d1.Print();
// 权限的平移
const Date d2(2025, 8, 14);
d2.Print();
return 0;
}取地址运算符重载分为普通和const,一般这两个函数编译器自动生成的就够用了,不用显式实现,但在一些特殊场景,例如我们不想让别人取到当前类对象的地址,就可以自己实现,返回一个虚拟地址
// 取地址运算符重载
class show
{
public:
// 非const对象的取地址运算符重载
show* operator&()
{
// 返回当前对象的地址
return this;
}
// 构造
show(int num = 0, char ch = '\0')
: _num(num),
_ch(ch)
{
// ...
}
// const对象的取地址运算符重载
const show* operator&() const
{
// 返回空指针作为示例,实际中应根据需求返回有意义的地址
return nullptr;
}
private:
int _num;
char _ch;
};
int main()
{
show obj1;
const show obj2;
std::cout << "非const对象的地址: " << &obj1 << std::endl;
std::cout << "const对象的地址: " << &obj2 << std::endl;
return 0;
}