C++/类与对象/默认成员函数@取地址函数(共两个,系列结束)

  在C++的类与对象中,有6个默认的成员函数,就是即便用户不编写定义,编译器也会自动生成的成员函数。
其中,有两个默认成员函数是,实现取对象地址的功能。因为实际中,根据类创建对象时,
有的对象设定是可读可写的;而有的对象要求只可读不可更改。对于这类对象,在创建对象时,会加上 const 修饰,表示为常量对象。而如果只使用一种取地址函数,对于这两种类型的取地址时,会有权限的放大缩小的问题。
所以分别针对这两种类型,类里面提供了两种默认的取地址成员函数,分别是
普通对象的取地址const对象的取地址。下面先对普通对象取地址的成员函数,展开学习。

( ps:
普通对象,没有用const修饰的对象
const对象,用const修饰的对象

注意: 取地址“ & ” 是一元运算符,所以对对象的取地址,本质上就是运算符重载函数。重载的操作符是 operator



普通对象的取地址函数

作用

获取不是const修饰的对象的地址。



函数特征

函数原型为: 返回值 operator&(参数) 。

函数名operator&
没有参数
③ 返回类型是类型指针

下面是函数的模型:

#include <iostream>
using namespace std;

class Date
{
public:
	// 获取普通对象地址的函数
	Date* operator&()    // 实际上被编译器处理为: Date* operator&(Date* this)
	{
		return this;
	}
};

以上,便是对于日期类Date,普通对象(没用const修饰的对象)的取地址函数。

下面来看一下,显式普通对象取地址函数的效果



显式普通对象的取地址函数

例子程序:

#include <iostream>
using namespace std;

class Date
{
public:
	// 获取普通对象地址的函数
	Date* operator&()    // 实际上被编译器处理为: Date* operator&(Date* this)
	{
		return this;
	}
};

int main()
{
	Date d1;
	cout << &d1 << endl;	// 打印输出对象d1的地址
	return 0;
}

运行结果:


对象d1的地址

控制台成功输出对象d1的地址。

这是对于普通对象,用户自己定义的普通对象取地址的函数的效果。
那么,当用户没有定义这一特殊函数,使用编译器自行生成的,会是什么效果呢?我们来进行验证:



隐式普通对象的取地址函数

例子程序:

#include <iostream>
using namespace std;

class Date
{

};

int main()
{
	Date d1;
	cout << &d1 << endl;	// 打印输出对象d1的地址
	return 0;
}



运行结果:


输出打印对象d1的地址

  我们发现,即便是没有编写定义对于普通对象取地址的函数。编译器使用自行生成的默认取地址函数,依旧能获取对象d1的地址。
  因此对于这个默认成员函数,一般都不用用户编写定义,使用编译器自行生成的取地址函数即可实现效果。除非是一些特殊情况,比如不想创建出的对象的地址被获取,那么便可以编写定义显式取地址函数,然后在函数里面,返回空指针nullptr。总之,特殊情况特殊对待、设计。一般情况下,使用编译器自行生成的即可。



以上,我们实现了对于普通对象的取地址。
那么对于const修饰的对象,是否能通过以上的成员函数获取到常量对象的地址呢?如:

#include <iostream>
using namespace std;

class Date
{

};

int main()
{
	Date d1;
	const Date d2;		// 常量对象d2
	cout << &d1 << endl;	// 打印输出对象d1的地址
	cout << &d2 << endl;	// 打印输出对象d2的地址
	return 0;
}



结果显示:

在这里插入图片描述

对象d2的地址,一样被输出打印出来了,怎么回事?
答:那是因为,编译器自行生成的对于常量对象取地址的成员函数,起到的作用。
下面对,这一默认成员函数,const修饰的对象取地址函数,进行学习。



const对象的取地址函数

作用

获取const修饰的对象的地址



函数特征

函数原型为: 返回值 operator&(参数) const

#include <iostream>
using namespace std;

class Date
{
public:
	// 获取const修饰的对象地址的函数
	const Date* operator() const    // 编译器处理成: const Date* operator(const Date* this)
	{
		return this;
	}
};

首先,我们现弄明白非得要有这个成员函数,使用上面的成员函数,难道就不能获取常量对象的地址吗?答案肯定是不能的。原因如下:

#include <iostream>
using namespace std;

class
{
public:
	// 普通对象取地址函数
	Date* operator&()	// 会被编译器处理为: Date* operator(Date* this)
	{
		cout << "operator&()" << endl;
		return this;
	}
	// const修饰的对象取地址函数
	const Date* operator&() const	   // 会被编译器处理为: Date* operator(const Date* this)
	{
		return this;
	}
}:

int main()
{
	Date d1;			// 普通对象d1
	const Date d2;		// 常量对象d2

	&d1;	//  实际上编译器会编译成:  d1.operator&(&d1)
	&d2;	//  实际上编译器会编译成:  d2.operator&(&d2)
	return 0;
}


要点:
  注意程序上给注释,当我们要获取对象d1的地址&d1时,编译器会将去调用对象类里的成员函数operator&() ,
并且将d1的地址传过去。在类中定义的显式普通对象取地址的成员函数中,函数中隐藏了一个参数:Date类型的指针 this 。 这时 this 指针和传过来的参数d1的地址类型匹配(d1地址存的数据类型是Date),因此能成功调用该函数,并且在函数里面返回this指针(对象的地址)。
  而对于对象d2来说,如果获取对象d2的地址&d2,调用的也是成员函数operator&()的话,会出现权限放大的问题。因为 operator&() 函数参数中隐藏的指针 this 是Date类型,而d2地址中存储的数据是const Date类型,是可读不可写的数据类型。 将可读不可写的地址传给可读可写指针,将会令指针的权限放大,而这是错误。所以为了解决这一问题,便有了const修饰的对象取地址的成员函数。
  而const修饰的对象取地址的成员函数解决的方法就是,参数匹配。将 this 指针的类型也设置为const Date类型,那么将不会出现权限放大的问题。又因为 this 指针是隐藏的参数,所以不可能在参数里面实现。因此 标准规定 ,在函数的旁边加个 const 即可。编译器会自行生成函数参数为: const Date* this 的格式,因此便解决了这一问题。



显示const对象的取地址函数

例子程序:

#include <iostream>
using namespace std;

class Date
{
public:
	// const对象的取地址函数
	const Date* operator&() const  // 实际上被编译器处理为: Date* operator&(const Date* this)
	{
		cout << "operator&() const" << endl;
		return this;
	}
};

int main()
{
	const Date d4;
	cout << &d4 << endl;	// 打印输出对象d4的地址
	return 0;
}

运行结果:


在这里插入图片描述


成功获取const修饰的变量d4的地址,并且程序确实是进入类中定义的取地址函数。



隐式const对象的取地址函数

例子程序:


#include <iostream>
using namespace std;

class Date
{

};

int main()
{
	const Date d5;
	cout << &d5 << endl;	// 打印输出对象d5的地址
	return 0;
}

运行结果:


在这里插入图片描述

我们发现,使用编译器自行生成的对于 const修饰的 对象取地址函数,依旧能够获取对象d5的地址。



总结:
  对于这两个取地址的默认成员函数,可以不必过于费心。一般情况下,使用编译器自行生成的默认成员函数即可实现取对象地址的功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值