【C++】常方法+常对象

引言

前一节类的编译流程中简单介绍了this指针的类型,但没说为什么是这种定义方式。this指针的原型就是类名* const this,其实也就是为什么*的右边需要加个const,原因很简单:害怕程序员修改this指针的值,比如说:置空this = NULL; 这种操作对代码的后续执行是致命的。


(一)this指针+const

看了引言的小伙伴就很疑惑,明明都已经说过了this加const的情况,那为何还有const可加??

这是之前讲过的栗子:

int a = 10;
int* const p = &a;
const int* const cp = &a; 

可以看到上面的p就相当于对象中的那个this指针的类型(依赖于对象),而cp就是我所谓的this指针+const了。很明显,并不重复。

C++中也为this指针提供了这种定义方式:(常方法)

返回值 方法名(形参列表)const;

()后面的const修饰的就是对应方法的第一个参数this指针,形式如下:const 类名* const this,这里的左const就是我们在()后面加的const,右const是编译器在编译时期加的。


(二)常对象

有一句话叫做:常对象只能调用常方法。上面已经讲述了常方法,那么这句话的意思也大概能够参透了。

这句话意味着:

  • 常对象只能调用常方法;
  • 普通对象可以调用所有方法;

下面我举个栗子解释下为什么是这样:

你能看出这段代码有什么问题吗??

#include <iostream>
using namespace std;
//设计个人类
class Person
{
public:
	Person();	//无参构造
	...
	int GetAge()const;	//常方法
	char* GetName();	//普通方法	
private:
	int age;
	char* name;
};
int main()
{
	//普通对象
	Person p1;		//假设已经初始化
	p1.GetAge();	//GetAge(&p1) 正确
	p1.GetName();	//GetName(&p1) 正确

	//常对象
	const Person p2;	//假设已经初始化
	p2.GetAge();		//GetAge(&p2)正确
	p2.GetName();		//GetName(&p2) 错误
	return 0;		
}

分析:

  • 先对p1分析:p1是一个Person类型的普通对象调用常方法GetAge(),编译器在编译阶段将该语句编译成GetAge(&p1);,使用const Person* const 类型的this指针指向p1的地址(Person*类型),能力缩小,这是完全可行的。那么GetName()也自然可行,编译成功
  • p2分析:p2的地址类型(const Person*),在调用常方法GetAge(),编译期间被改写成GetAge(&p2),此时使用const Person* const this指针指向p2,未对p2的产生影响,可行,编译成功。但是在调用GetName()时,此时的this指针是Person* const类型,而p2的地址(const Person*),this保存p2的地址扩大了p2的能力,编译不通过所以常对象只能调用常方法

(三)this指针的传递方式

this指针的调用跟调用约定相关。

(1)thiscall调用约定

thiscall仅仅应用于C++成员方法。

lea ecx,[p1]	;将p1地址给ecx寄存器
mov [this], ecx  ;将ecx中的值给this指针

在这里插入图片描述

(2)__cdecl调用约定

在这里插入图片描述

结论:__cdecl 比 thiscall 多了一次push和pop

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值