在C++中,常提到一句话,就是常对象只能调动常方法,普通对象能够调动所有方法,那么这个原理何在呢?
首先,应当明白,C++面向对象的编程思想是仅仅在程序的编写中进行的,在计算机进行编译链接过程的时候计算机是要将其转变为汇编语言和机器语言的,最终生成执行的依然是面向过程的,这样计算机才能够识别调用。
所以我们举个例子:
class goods{
private:
string Name;
float prince;
int num;
public:
float getprince() const{return prince;};
int getnum(){return num;};
};
int main()
{
goods a1;
const goods a2;
a1.getnum();
//a2.getnum();会报错
a1.getprince();
a2.getprince();
}
我们可以发现,const修饰的a2不能调动getnum方法,只能调用getprince方法,而没有被const修饰的a1则两个方法都可以调动。
那么归根结底是为什么呢?
这就涉及到C++的编译了,编译器对C++进行编译我们所写的
a1.getnum();
时,程序编写中我们认为是调用了a1对象的getnum方法,但是计算机并不会为每一个对象都生成一个空间来保存方法,而是所有类型的方法都被保存在了同一个区域,也就是“公共代码区”。
实际执行只是一个
getnum();
那么既然存放在公共代码区那么在调用的时候,一个公共代码区对应着多个数据区,该调用哪个呢?不难看出,后面这个和前面的区别,那就是a1这个对象,实际上a1的地址会被传递过去,保存在this指针中,而我们常常认为的调用对象内属性的操作实际上也都是通过this指针来完成的,最终调用函数实际上执行的是这样的代码。
getnum(&a1);
而方法实现的也不是直接按照函数体进行执行,而是编译器会将函数体修改成这样来执行:
int getnum(goods* const this){return this->num;}
这也就解释了为什么常方法不能调用普通方法
因为常方法会在this指针前加const,回到我们这个例子里就是getprince方法最终执行的方法体其实是这样的
float getprince(const goods* const this){return this->prince;}
this的指向和自身都被const修饰,也就不能对于this指向的goods对象进行修改,被const修饰的a2不会产生能力扩展的问题。
而如果调用getnum方法,this指针自身被const修饰,但是指向没有被修饰,也就产生了能力扩展,有对a2属性进行修改的风险,所以就不能让a2这一常对象调用普通方法。