普通成员函数
当我们定义一个类,例如:
class Test {
public:
Test(int val = 0) : data_(val) { }
void Show() {
cout << data_ << endl;
}
private:
int data_;
}
随后我们在使用这个类时,会创建相对的类对象,不同的对象拥有自己独立的数据(static 对象-这里把内置内置类型定义的变量也成为对象,为所有类对象共有),那么不同对象拥有的数据成员和成员函数在内存中是如何布置的呢?
显然不同对象的数据之间肯定是独立的,只有 static 对象供所有对象使用,在不同的对象中只存在一份拷贝,这在逻辑上也是合理的。现在我们考虑不同对象的成员函数可不可以共享,我们知道在封装一个类时,我们定义的是一组数据和一组在数据上的操作,分别对应类的数据成员和成员函数。不同的数据对于函数来说都是一样的概念,定义函数的目的之一就是为了代码重用,现在放到不同对象之间的角度来考虑,我们也没有必要让每个对象都持有一份所有成员函数的代码拷贝,只需要指出当前对象需要调用的函数就行。
Test t0(0);
Test t1(1);
t0.Show(); // 实际上是 t0.Show(this),this 是当前对象的地址,
// 类型为 Test * const,因为对象的地址不会改变,
// 所以这里 this 是一个常量指针
t1.Show(); // 同上
之前我们说不同对象会共用一份成员函数代码,那么一个对象在调用其成员函数时就需要寻找数据成员的位置,这里 this 就是当前对象的地址值,有了 this 以后成员函数就得以找到每个类的数据成员所在地址了。(如果不同对象没有共享一份成员函数代码的话,那么在这里也就不需要 this 这个隐式参数了,因为成员函数可以根据自己的地址值和偏移量来找到数据成员所在地址)
常成员函数
当我们定义一个常量对象然后调用 Show 函数时会发现编译器会报错,
Test const t2(2);
t2.Show();
我们也可以想到常量对象是不可以被修改的,但是 Show 函数并没有限制它不会修改 t2 的内容,既然你无法保证不修改我 const 对象那么编译器就表示我不干了,并提醒你出错,Show 函数完全可以修改 t2 的内容。所以要定义一个常量对象可以调用的函数,那么这个函数得保证它不会修改对象的值。我们还知道成员函数是通过 this 找到各个对象的数据成员的,那么我们传一个指向常量的 this 不就可以解决这个问题了吗?但是 this 参数的传入不是由我们完成的,我们无法那样做,于是 c++ 规定当要定义一个常成员函数时在函数参数列表后加上一个 const 就表示这是一个常成员函数,不会修改对象的内容(这里有列外,当一个对象加上 mutable 关键字时即使在常成员函数内部也可以修改其值,而不会报错,还有关于怎样定义没有修改一个对象的内容,effective c++ 条款3 有详细的说明)this 的 类型为 Test const * const。
class Test {
public:
Test(int val = 0) : data_(val) { }
void Show() const {
cout << data_ << endl;
}
private:
int data_;
}
这样定义类时,我们定义一个类的常量对象就可以使用 Show 函数了。