C++ には言語の一部としてフィールド アクセサーがないことについて の記事を読んでいました。
投稿の最後で、著者は、クラスのフィールド アクセサーをエミュレートするマクロ ベースのソリューションを提供します。
// 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);
};
これをプリプロセッサで実行すると、次のようになります。
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;
};
アイデアは、私自身の実装も追加したであろうということです:
int get_visitCount();
void set_visitCount(int v);
そして、あたかもvisitCount
直接アクセスされているように見えます。
ただし、関数は実際には舞台裏で呼び出されます。
Node n;
n.visitCount = 1; //actually calls set method
cout << n.VisitCount; //actually calls get method
囲んでいるクラスにアクセスするこのトリックについて詳しく知りたいです。
((Node*)((char*)(this) - (((char*)&((Node*)(0xffff))
の関連性は0xffff
何ですか?
10 進数では: 65535
.
これはどのようにコンパイラをだまして、visitCount クラスを囲むクラスにアクセスさせるのでしょうか?
また、これは MSVC では機能しないこともわかっているので、このハックが行っていることを達成する標準的な方法があるかどうか疑問に思っていました。