C++必知必会 - 指向类的数据成员的指针并非指针

普通指针使用*来标示,而指向类的成员函数的指针使用ClassName::*标示。需要注意的是,指向类的数据成员的指针并非指针,因为它既不包含地址,行为也不像指针

与常规指针不同,一个指向成员的指针并不指向一个具体的内存位置,它指向的是一个类的特定成员,而不是指向一个特定对象里的特定成员。通常最清晰的做法是将指向数据成员的指针看作 为一个偏移量 C++标准并没有说该如何实现指向成员的指针,大多数编译器都将指向数据成员的指针实现为一个整数,其中包含被指向成员的偏移量。另外加上1(加1是为了让0值可以表示一个空的数据成员指针)。 这个偏移量告诉你,一个特定成员的位置距离对象的起点有多少个字节。一个类成员的偏移量在任何对象中都是相同的。

给定一个成员在类内的偏移量,为了访问位于那个偏移量的数据成员,我们需要该类的一个对象的地址。这时候就需要.*和->*这两个看上去非同寻常的操作符闪亮登场了。

//------

    class C { 
      public: 
        //...
        int a_; 
    }; 
    int C::*pimC; // 一个指针,指向C的一个int成员 
    C aC; 
    C * pC = &aC; 
    pimC = &C::a_; 
    aC.* pimC = 0 ; 
    int b = pC - > *pimC;

//------

当写下pC->*pimC时,其实是请求将pC内的地址加上pimC内的偏移量,为的是访问pC所指向的C对象中适当的数据成员。当写aC.*pimC时,是在请求aC的地址加上pimC中的偏离量,也是为了访问pC所指向的C对象中适当的数据成员.

 

另外,存在从指向基类成员的指针到指向公有派生类成员的指针的隐式转换,但不存在从指向派生类成员的指针到指向其任何一个基类成员的指针的转换。这个可以从c++对象的内存布局来理解,因为基类成员一般在子类对象的前部分,所以这些成员在基类或者子类中的偏移是一样的;解析的时候,就是对象的首地址加上这个偏移量来获得真正的数据成员:理解了这一点,你就知道有虚继承的类中,与虚基类的相关转化是非法的。


同样,指向类的非静态 成员函数的指针也不是指针,不是一个地址,而是一个指向成员函数的指针

为了访问该成员,需要将对象的地址(this指针)和成员的偏移量(包含于指向数据成员的指针中)相加。对于指向成员函数的指针的情形,需要将对象的地址用作(或用于计算)this指针的值,进行函数调用,以及作为其他用途。

指向成员函数的指针也表现出一种逆变性,即存在从指向基类成员函数的指针到指向派生类成员函数指针的预定义转化,反之不然。这很好理解,如果考虑到基类成员函数会试图通过其this指针访问基类成员,然而派生类函数可能会试图反问基类中不存在的成员的话。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值