lundi 25 mai 2015

How is the compiler tricked into providing a pointer to the enclosing class?

I was reading an article on how C++ does not have field accessors as part of the language.

At the end of the post, the author gives a macro based solution that emulates field accessors for classes:

// a little trick to fool compiler we are not accessing NULL pointer here
#define property_offset(type, name) \
  (((char*)&((type*)(0xffff))->name) - (char*)(0xffff))

#define property_parent(type, name) \
  ((type*)((char*)(this) - property_offset(type, name)))

// macro defining property
#define property(type, name, parent)                                         \
  struct name##_property {                                                   \
    operator type() { return property_parent(parent, name)->get_##name(); }  \
    void operator=(type v) { property_parent(parent, name)->set_##name(v); } \
                                                                             \
   private:                                                                  \
    char zero[0];                                                            \
  } name

// our main class
class Node {

  /* visitCount will act as a field accessor */
  property(int, visitCount, Node);
};

When I run this through the preprocessor, I get:

class Node {

  struct visitCount_property {
    operator int() { return ((Node*)((char*)(this) - (((char*)&((Node*)(0xffff))->visitCount) - (char*)(0xffff))))->get_visitCount(); }
    void operator=(int v) { ((Node*)((char*)(this) - (((char*)&((Node*)(0xffff))->visitCount) - (char*)(0xffff))))->set_visitCount(v); }    
    private: char zero[0];
    } visitCount;
};  

The idea being that I would have also added my own implementations of:

int get_visitCount();
void set_visitCount(int v); 

And it would look as if visitCount was being directly accessed.
However, the functions would actually be called behind the scenes:

Node n;
n.visitCount = 1;     //actually calls set method
cout << n.VisitCount; //actually calls get method  

I'd like to know more about this trick of accessing the enclosing class:

((Node*)((char*)(this) - (((char*)&((Node*)(0xffff))

What is the relevance of 0xffff?
In decimal that is: 65535.

How does this trick the compiler to accessing the class that encloses the visitCount class?

I also see that this does not work on MSVC, so I was wondering if there was a standard way of accomplishing what this hack is doing.

Aucun commentaire:

Enregistrer un commentaire