清楚以下几点:

  1. C++的类的非静态成员是共享的,即所有相同类的对象共享的是同一份非静态成员函数。即类的非静态成员函数是不依赖于对象存在的。

  2. 的编译器在处理非静态成员函数时,会在其参数列表中添加一个this指针,this指针指向的便是具体调用该非静态成员函数的对象的起始地址。该非静态成员函数中需要的所有的成员数据都是通过这个this指针获取的。



通过以下几个小例子给予说明:

#include <iostream>
using namespace std;
class A
{
    int m1;
    int m2;
public:
    void fun1()
    {
        cout<<"call fun1 success!"<<endl;
    }
    void fun2()
    {
        cout<<&m1<<' '<<&m2<<endl;
        cout<<"call fun2 success!"<<endl;
    }
    void fun3()
    {
        cout<<this<<endl;
        cout<<&m1<<endl;
        cout<<sizeof(*this)<<endl;
        cout<<"call fun3 success!"<<endl;
    }
    void fun4()
    {
        cout<<m1<<' '<<m2<<endl;
        cout<<"call fun4 success!"<<endl;
    }
};
int main()
{
    ((A*)0)->fun1();
    A *pa = 0;
    pa->fun1();
    pa->fun2();
    pa->fun3();
    pa->fun4();
    return 1;
}

输出结果:

call fun1 success!

call fun1 success!

00000000 00000004

call fun2 success!

00000000 00000000

8

call fun3 success!

然后程序崩溃。


对于输出的第一个和第二个call fun1 success! 可以说明哪怕调用的对象地址是从任意一个整数转换来的或者是一个空指针,仍然可以调用类的非静态成员函数,当然这里的非静态成员函数不能访问具体对象的数据成员,因为这里的数据部分不存在。fun4便访问了数据成员,结果程序崩溃了。充分说明了第一点。


对于第三行和第四行的输出,为什么能够输出成员数据的地址(其实并不是真正的成员数据的地址),请参考 C++的数据成员访问方式


对于第五,六,七行的输出,说明this指向的地址和m1的地址是一样的,而且this指向的结构体的大小和类的数据成员的大小一致。即this是对象的数据部分的起始地址(数据部分包括虚指针,而且是放在最低地址处的,该例子中没有虚函数,所以this的值和第一个数据成员的地址相同,如果有虚函数,则会有4个B的偏移)。大家可以用真正的对象地址来做试验,会发现结果一致。


程序崩溃的原因便是,通过一个任意转换而来的对象指针去访问成员数据时出错了,因此实际并不存在该对象,也就不用谈访问对象的数据部分了。


有什么问题,欢迎大家一起讨论!