给C++添加属性机制(继,得到成员在类中的偏移)

接上篇,时间不够,写得较乱
我上一篇给C++添加属性机制的文章中,让属性类得到目标类的类指针,我使用了一个INIT_PROPERTY宏,在前几天和龙子龙孙聊天时,他告诉了我一个技巧,得到类成员在类中的偏移地址,如下
(int)(&((type_name*)NULL)->member_name)
例如我有个类 A
class A
{
public:
    virtual int show() {}
    int i1, i2;
};

则 (int)(&((A*)NULL)->i2) == 8   
类地址+8的偏移处为i2的地址(4字节vmt表地址,4字节i1,所以i2的寻址偏移为8)

恍然大悟,这样我就能在属性类中自己计算出拥有属性类的类的地址了,这是因为类的寻址方式决定的,如下所示:
class Child
{
public:
  int i1, i2;        i1偏移为0, i2为4,无vmt表
};

class Parent
{
public:
   int i;             i偏移为0
   Child  *c;            c偏移为4
   Parnet() {...}        c的new 和 delete就不写了
};
Parent *p;
这时要new一个Parent类时,会在堆上分配二块内存,一块为c对象占用内存,一块为p对象占用内存.
要寻址类P对象中c对象的i2成员(p->c->i2),大概的汇编代码如下:
mov ecx, p                                //得到p的指针
mov ecx, [ecx + 4]                    //得到p对象成员c的指针
mov eax, [ecx + 4]                   //得到c对象成员i2的地址
这样就寻址到了i2

但如果Parent类不是包含的Child类的指针,而是直接包含的对象,情况就不一样了,如下:
class Parent
{
public:
   int i;             i偏移为0
   Child  c;      c偏移为4(注意不同,这里c不是Child*了)
};
Parent *p;
这时要new一个Parent类时,只会在堆上分配一块内存,为p对象占用内存,c对象包含在p对象内,直接使用p对象的内存,要寻址类P对象中c对象的i2成员(p->c.i2),大概的汇编代码如下:
mov ecx, p                                //得到p的指针
mov ecx, ecx + 8                     //得到i2的地址 8 = c偏移+i2在c类中的偏移,编译优化
要寻址类P对象中c对象的地址,如下:
mov ecx, p                                //得到p的指针
mov ecx, ecx + 4                     //得到c的地址 p对象指针+偏移
从上面可以看出,只要知道c类地址,要得到p的指针,就 c地址 - c对象在p对象中的偏移就行了.
事情就简单了,示例代码如下:
#include <iostream>

using std::cout;
using std::cin;
using std::endl;

template<typename T, typename int(*GetOffset)()>
class Property
{
public:
    Property()
    {
        cout << "this:" << (int)this << std::endl;
        cout << "owner:" << (int)this - GetOffset() << std::endl;
    }
};

#define PROPERTY_DECLARE(pro_name, type_name)/
    private: int inline static pro_name##_offset() {return (int)(&((type_name*)NULL)->pro_name);};/
    public: Property<type_name, type_name::pro_name##_offset> pro_name;

class PropertyTest
{
public:
    int i;
public:
    PROPERTY_DECLARE(Name, PropertyTest)
};

int main()
{
    PropertyTest *test = new PropertyTest();
    cout << std::endl;
    cout << "property address:" << (int)(&test->Name) << std::endl;
    cout << "test class address:" << (int)test << std::endl;

    std::cin.get();
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值