C++:类中两个易被忽略的默认函数
C++的自定义类中有六个默认的函数,即如果用户没有显式定义这些函数时,C++编译器会类中生成这些函数的默认形式。除了大家所熟知的构造函数、拷贝构造函数、赋值函数和析构函数外,C++为自定义类 还提供了两个容易被人忽视的默认函数——取地址函数和对常对象的取地址函数。
一、取地址函数
在C++中可以通过取地址运算符&求得变量的地址,如:
int a=;
cout<<"变量a的地址为:"<<&a<<endl;

那么对于自定义类的对象是否可以通过取地址运算符&求得对象在内存中的地址呢?我们先来看个例子:
#include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用无参数的构造函数"<<endl;
}
Student(string name,int age):Name(name),Age(age){
cout<<"调用有参数的构造函数"<<endl;
}
Student(const Student& stu){
cout<<"调用拷贝构造函数"<<endl;
Name=stu.Name;
Age=stu.Age;
}
Student& operator=(const Student& stu){
cout<<"调用赋值函数"<<endl;
if(this!=&stu){
Name=stu.Name;
Age=stu.Age;
}
return *this;
}
~Student(){
cout<<"调用析构函数"<<endl;
}
private:
string Name;
int Age;
};
int main(){
Student stu("Tomwenxing",);
cout<<"对象stu的地址为:"<<&stu<<endl;//成功:运行对对象stu进行取地址操作
return ;
}

由上面的例子可知,C++允许通过取地址运算符&求得对象在内存中的地址,而这个功能就是依靠类中的取地址函数实现的。和赋值函数相似,类中的取地址函数是通过对取地址运算符&进行重载来实现的,如果用户在编写类时没有显式地定义类的取地址函数,那么C++编译器将会在类中生成一个默认的取地址函数。
#include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用无参数的构造函数"<<endl;
}
Student(string name,int age):Name(name),Age(age){
cout<<"调用有参数的构造函数"<<endl;
}
Student(const Student& stu){
cout<<"调用拷贝构造函数"<<endl;
Name=stu.Name;
Age=stu.Age;
}
Student& operator=(const Student& stu){
cout<<"调用赋值函数"<<endl;
if(this!=&stu){
Name=stu.Name;
Age=stu.Age;
}
return *this;
}
25 Student* operator&(){ //取地址函数
26 cout<<"调用取地址函数"<<endl;
27 return this;
28 }
~Student(){
cout<<"调用析构函数"<<endl;
}
private:
string Name;
int Age;
};
int main(){
Student stu("Tomwenxing",);
cout<<"对象stu的地址为:"<<&stu<<endl;//成功:运行对对象stu进行取地址操作,该语句相当于stu.operator&();
return ;
}

二、对常对象的取地址函数
还是上面的例子,这次我们队常对象进行取地址操作,看看会发生什么:
#include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用无参数的构造函数"<<endl;
}
Student(string name,int age):Name(name),Age(age){
cout<<"调用有参数的构造函数"<<endl;
}
Student(const Student& stu){
cout<<"调用拷贝构造函数"<<endl;
Name=stu.Name;
Age=stu.Age;
}
Student& operator=(const Student& stu){
cout<<"调用赋值函数"<<endl;
if(this!=&stu){
Name=stu.Name;
Age=stu.Age;
}
return *this;
}
25 Student* operator&(){
26 cout<<"调用取地址函数"<<endl;
27 return this;
28 }
~Student(){
cout<<"调用析构函数"<<endl;
}
private:
string Name;
int Age;
};
int main(){
const Student stu("Tomwenxing",);
cout<<"对象stu的地址为:"<<&stu<<endl;//成功:运行对对象stu进行取地址操作
return ;
}

通过上面的例子我们发现,在对常对象stu进行取地址操作时,对象并没有调用类中的取地址函数,这是因为类中还有一个默认的函数,其功能是对常对象进行取地址操作。和取地址函数相同,对常对象的取地址函数也是通过对取地址运算符&重载来实现的,同样如果用户在编写类时没有显式地定义类的对常对象的取地址函数,那么C++编译器将会在类中生成一个默认的对常对象的取地址函数:
#include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用无参数的构造函数"<<endl;
}
Student(string name,int age):Name(name),Age(age){
cout<<"调用有参数的构造函数"<<endl;
}
Student(const Student& stu){
cout<<"调用拷贝构造函数"<<endl;
Name=stu.Name;
Age=stu.Age;
}
Student& operator=(const Student& stu){
cout<<"调用赋值函数"<<endl;
if(this!=&stu){
Name=stu.Name;
Age=stu.Age;
}
return *this;
}
25 Student* operator&(){
26 cout<<"调用取地址函数"<<endl;
27 return this;
28 }
29 const Student* operator&() const{
30 cout<<"调用对常对象的取地址函数"<<endl;
31 return this;
32 }
~Student(){
cout<<"调用析构函数"<<endl;
}
private:
string Name;
int Age;
};
int main(){
const Student stu("Tomwenxing",);
42 cout<<"对象stu的地址为:"<<&stu<<endl;//成功:运行对常对象stu进行取地址操作
return ;
}

特别注意:两个const的作用
• 第一个const要求函数返回的指针是常量,如果返回的是非常量则报错
• 第二个const修饰this指针,使该对象的this指针是一个指针常量,从而能够被该函数成功返回。
C++:类中两个易被忽略的默认函数的更多相关文章
- httpservlet类中两个service方法
在浏览器访问html页面时,当数据提交给servlet时发生了什么,这是我们需要了解的. 1.我们需要了解一下servlet的继承体系. servlet接口 ------->GenericSer ...
- C++类中的static数据成员,static成员函数
C++类中谈到static,我们可以在类中定义static成员,static成员函数!C++primer里面讲过:static成员它不像普通的数据成员,static数据成员独立于该类的任意对象而存在, ...
- python类中两个列表实例如何相加或相减
如下 import numpy a = [1, 2, 3, 4] b = [5, 6, 7, 8] a_array = numpy.array(a) b_array = numpy.array(b) ...
- 解决同一页面中两个iframe互相调用jquery,js函数
这一个月又没更新博客,唉,懒癌又犯了,今天解决了一个问题,关于两个iframe互相调用jquery函数方法 a.html中有两个iframe,如下: <iframe width="10 ...
- cocos2dx lua 绑定之二:手动绑定自定义类中的函数
cococs2dx 3.13.1 + vs2013 + win10 1.首先按照<cocos2dx lua 绑定之一:自动绑定自定义类>绑定Student类 2.在Student类中增加一 ...
- python: 面向对象:类和对象调用类中的变量和方法
一. 面向对象初识 我们在生活中做事都是面向过程的,前面实现一些基本逻辑功能代码也是用面向过程的语句实现的,后来学了函数,把这些功能又装到了函数里.但用面向过程的方法去写程序,只能实现一个功能,我们要 ...
- [Python之路] object类中的特殊方法
一.object类的源码 python版本:3.8 class object: """ The most base type """ # d ...
- spring boot:使用validator做接口的参数、表单、类中多字段的参数验证(spring boot 2.3.1)
一,为什么要做参数验证? 永远不要相信我们在后端接收到的数据, 1,防止别人通过接口乱刷服务:有些不怀好意的人或机构会乱刷我们的服务,例如:短信接口, 相信大家可能很多人在工作中遇到过这种情况 2,防 ...
- C++:调整基类成员在派生类中的访问属性的其他方法(同名成员和访问声明)
4.3 调整基类成员在派生类中的访问属性的其他方法 4.3.1 同名函数 在定义派生类的时候,C++语言允许在派生类中说明的成员与基类中的成员名字相同,也就是 说,派生类可以重新说明与基类成员同名的成 ...
随机推荐
- Html+Css实现梯形选项卡
1,先看一下效果图 2,梯形通过定位和设置Border来实现的,平行四边形通过旋转来实现的. 3,代码如下 (1)HTML代码 <html lang="en" xmlns=& ...
- (oralce)pga_aggregate_target与workarea_size_policy相互关系验证
pga_aggregate_target与workarea_size_policy相互关系验证 先放上结论: 1. 当pga_aggregate_target设置为非0, 手工设置(workarea ...
- 使用C语言给php写扩展
1.在php源码路径的ext文件夹下,新建一个extend_test.def文件,编辑文件内容为 string my_test_function(string str,int n) 2.在当前目录执行 ...
- 四、Delphi10.3读取JSON数据
一.我们有一段JSON数据如下: { "五班": [ { "姓名": "张三", "成绩": 75.5 }, { &qu ...
- slice扩容
1.当向切片新加入数据,原切片数据加上新数据长度不超过切片容量时,直接加入切片末尾,容量大小不变. 2.当加入新的数据后,数据长度超出原切片的容量大小2倍,则切片的容量会是数据长度(偶数)或数据长度( ...
- 论文阅读---Reducing the Dimensionality of Data with Neural Networks
通过训练多层神经网络可以将高维数据转换成低维数据,其中有对高维输入向量进行改造的网络层.梯度下降可以用来微调如自编码器网络的权重系数,但是对权重的初始化要求比较高.这里提出一种有效初始化权重的方法,允 ...
- Caffe中Layer注册机制
Caffe内部维护一个注册表用于查找特定Layer对应的工厂函数(Layer Factory的设计用到了设计模式里的工厂模式).Caffe的Layer注册表是一组键值对(key, value)( La ...
- 22-[jQuery]-选择器, js jQuery对象转换
1.基础选择器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- 【CJOJ2433】陌上花开 CDQ分治
[CJOJ2433]陌上花开 CDQ呲嘚秋分治 WA果然呲嘚秋分治跑得比树套树还快!!!(md理论复杂度不是一样的吗) 但树套树不知道比呲嘚秋高到哪里去辣装X用 Orz hzwer 第一维sort,第 ...
- SSISDB1:使用SSISDB管理Package
SSISDB 系列随笔汇总: SSISDB1:使用SSISDB管理Package SSISDB2:SSIS工程的操作实例 SSISDB3:Package的执行实例 SSISDB4:当前正在运行的Pac ...