c++常成员函数和常对象的注意事项

1.什么是常成员函数

常成员函数,它就是在成员函数后面加一个const,用来修饰this指针所指的对象,使this指针所指的对象不受更改,保护它的数据安全。当常成员函数没有参数的时候修饰的是this指针,有参数的时候参数不受影响,还是修饰的this!!常成员函数内部可以引用const数据成员,也可以引用非const数据成员。总之,常成员函数只是限定了使用此常成员函数的引用对象(this)不发生改变而已,没别的意思其实这样做的目的是为了与常对象相匹配,因为常对象只能调用它的常成员函数。可以参考谭浩强c++p90。

int getId() const
	{
		return this->id;
	}

比如上面的成员函数就是一个常成员函数,const是修饰this指针所指的对象的,我们知道this指针其实就是一个指向对象的常指针,另外说一句c++中的引用也是传递的常指针,那么这个常成员函数可以表示成这样(假设它是我定义的Student类里面的常成员函数):

int getId(const Student * const this)
	{
		return this->id;
	}

其实常成员函数的内部实现就是上面这样的,只是我们不这样书写,后面的const修饰的是this指针(即这个this指针不能再加减,成为一个常量),前面的const修饰的是这个this常指针所指的对象(即这个对象不受改变)。

2.常对象和常成员函数应该注意的事情

我们先看一个demo

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//创建一个Student类,包含id和name
class Student
{
private:
	int id;
	char *name;
public:
	Student(){
		this->id = 0;
		this->name = NULL;
	}
	Student(int id, char *name) {
		this->id = 0;
		int len = strlen(name);
		this->name = new char[len + 1];
		strcpy(this->name, name);
	}
	int getId() const
	{
		return this->id;
	}
	~Student() {
		if (name != NULL) {
			delete name;
			name = NULL;//当光标在这个位置的时候按 Shift+},光标就会跳到下面的大括号外
		}
	}
};

//全局函数display是为了接受一个Student对象的引用,然后为了保证display函数不会修改这个引用对象,就在前加了一个const修饰
//但是在用std.getId()输出的时候爆出错误:对象含有与成员函数Student::getId不兼容的类型限定符,对象类型是const Student
//解决的办法就是在对象的成员函数int getId(){}后面加一个const,修饰this指针所指的对象,让这个所指的对象不发生改变。
//关键有一句话:常对象只能调用它的常成员函数,下面display函数中接收的是常对象的std,所以只能调用常成员函数,而Student类中的成员函数又不是常成员函数,所以就在函数后加个const变成常成员函数。
void display(const Student & std) { 
	cout << std.getId() << endl;
}

int main() {
	//创建一个Student对象
	Student s1(1, "zhang3");
	//调用全局函数display
	display(s1);
}

根据以上demo我们知道,如果在display()的形参中加了一个const修饰的话,那么里面调用的getId()函数也需要在Student类里面声明为const 常成员函数。当然如果形参中不加const修饰的话就不存在这个问题了。那这个问题怎么来解释了,可以从两个角度来解释,如下:

解释一:我们看display函数中Const Student &std,表示这个传进来的Student对象是不能修改的,但是在调用std.getId()的时候,getId()会把std对象通过this指针传到这个函数里面去(只是不需要把this显示出来而已,但是实际上就这样操作了),相当于这个getId()是下面这样的:

 

int getId(Student * const this)
	{
		return this->id;
	}

那么也就是说,这个student对象从一个Const Student 赋值给了 Student ,这触发了c++的安全检测机制,就是“非常的”可以赋值给“常的”,但是“常的”不能赋值给“非常的”,因为这个破坏了“常的”安全,那岂不是就能改变了吗,所以c++要求不能这样做。

所以,当我们在getId()后加上cost之后,就变成了下面这个样子了:

int getId(const Student * const this)
	{
		return this->id;
	}

即:this指针所对应的对象不会改变还是常的!所以Const student还是赋值给了Const student。但是this指针也是不可见的,所以,最终的做法就是在getId()后面加个const!

解释二:也可以从另外一个角度来解释,我们看display()的形参中,不是给Student &std加了一个const修饰吗,就变成了

const Student & std,这是什么?这是常对象,也就是将一个普通的对象接收后变成了一个常对象,常对象只能调用它的常成员函数而不能调用该对象的普通成员函数。所以,如果想要std.getId(),那么这个函数getId()必须是常成员函数,还有一个需要注意的点,常成员函数不能改变数据成员,其实也不用死记,你都定义成常的了,你还去改变它干嘛。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值