深度探索C++对象模型----data member的存取

Static Data Members
    程序代码片段:
     class Point3d{
        public:
            .....
        private :
            float x;
            static List<Point3d*> *freeList;
            float y;
            static const int chunkSize = 250 ;
            float z ;
            .....
        };
      每一个static Data member只有一个实例,存放在程序的Data segment之中。每次程序取用static member时,就会被内部转化为对唯一extern实例的直接参考操作。
      // origin.chunkSize ==250
     Point3d::chunkSize == 250;
     //pt->chunkSize ==250
     Point3d::chunkSize==250;
      从指令执行的观点来看,这是C++语言中“通过一个指针和通过一个对象来存取member,结论完全相同”的唯一一种情况。 member其实并不在class Object之中,因此存取static members并不需要通过class Object。

       但如果chunkSize是一个从复杂继承关系中继承而来的member,又当如何?或许他是一个virtual base class 的 virtual base class 的member也说不定,但是程序之中对于static members还是只有唯一一个实例,而其存取路径还是那么直接。
        如果static Data member是经由函数调用,或其他某些语法而别存取呢?举个例子:
        foobar().chunkSize == 250;
        调用foobar()会发生什么事?下面是一种可能的转化:
        (void)foobar();
        Point3d::chunkSize ==250;
        
        若取一个static Data member的地址,会得到一个指向其数据类型的指针,而不是一个指向其class member的指针,因为static member并不内含在一个class Object之中。例如:
        &Point3d::chunkSize;
        会获得类型如下的内存地址:
        const int*;

        如果两个class都声明了一个static member chunkSize,那么当它们都被放在程序的Data segment中,就会导致名称冲突。编译器的解决方法是暗中对每一个static Data member编码(name-mangling),以获得独一无二的程序识别代码。name-mangling都有两个重点:
        1.一个算法,推导出独一无二的名称。
        2.独一无二的名称可以轻易被推导到原来的名称。

Nonstatic Data Member
         Nonstatic Data Member直接存放在每一个class Object之中。
      除非经由显示的explicit或者隐式的implicit class Object,否则没有办法直接存取它们。只要程序员在一个Member function中直接处理一个Nonstatic Data Member,所谓的”implicit class Object“就会发生。例如下面这段代码:
      Point3d Point3d::translate(const Point3d &pt){
            x+=pt.x;
            y+=pt.y;
            z+=pt.z;
      }
      这里对于x,y,z的直接存取,事实上是由一个implicit class Object(由this指针表达)完成的。事实上这个函数的参数是:
       //member function 的内部转化
        Point3d Point3d::translate(const Point3d &pt,Point3d *const this){
            this->x +=pt.x;
            this->y +=pt.y;
            this->z +=pt.z;
        }
        欲对一个Nonstatic Data Member 进行存取,编译器需要把class Object的起始地址加上Data Member的偏移地址(offset).
        如:
        origin._y = 0.0;
    那么地址&origin._y将等于:
    &origin+(&Point3d::_y-1);
    请注意其中的-1操作。指向Data Member的指针,其offset值总是被加上1,这样可以使编译器区分出”一个指向Data Member的指针,用以指出class的第一个Member”和“一个指向Data Member的指针,没有指出任何Member”两种情况。
    每一个Nonstatic Data Member的偏移位置(offset)在编译时期即可获知,甚至如果Member属于一个base class subobject也是一样的。因此存取一个Nonstatic Data Member,其效率和存取一个C struct Member或一个nonderived class的Member一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值