世の中には知っていても「ほとんど悪にしかならない」知識があります。
例えば、簡易爆弾の作り方や、内鍵を糸だけで開ける方法などです。
さて、ここに誰かが定義したクラスがあります。
1 2 3 4 5 6 7 8 |
// someone_defined.hpp class SomeoneDefined { void private_func(); protected: void protected_func(); public: void public_func(); }; |
このクラスを使う側はpublic_func()しか呼べません。当たり前です。
1 2 3 4 5 6 7 8 |
#include "someone_defined.hpp" int main() { SomeoneDefined sd; sd.public_func(); // OK sd.private_func(); // Error!!! プライベートメンバだぞ! return 0; } |
private_func()にアクセスするにはどうすればいいでしょうか。
色々考えられます。
このクラスの設計者の家に押しかけてアクセスレベルの変更を迫るのも有力な手段です。また、我々はプログラマなので、お気に入りのエディタ(例えばEmacs)でおもむろにsomeone_defined.hppを開き、内容を勝手に書き換えてしまうのも悪くありません。
もっと(C++使い的に)スマートな方法もあります。
someone_defined.hppの内容を一切書き換えることなく、SomeoneDefinedクラスの内容に好きなだけアクセスする方法。
こちらを御覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#define class struct // classをstructに! #define protected public // protectedをpublicに! #include "someone_defined.hpp" #undef protected #undef class int main() { SomeoneDefined sd; sd.public_func(); // OK sd.private_func(); // OK sd.protected_func(); // OK return 0; } |
はい、一丁上がりです。
someone_defined.hppは自分が何をされたのか気づいてすらいません。
この手法を悪ではなく正義の為に活かしましょう。(そんなものはない)
この悪魔のような手法からアナタの大切なクラスを守る方法はPimplイディオムを使って、完全に内部実装を隠蔽することです。
あと、悪魔には悪魔払いを!というわけで、こういう魔のモノを拒絶する方法もあります。
1 2 3 4 5 6 7 8 |
#if !defined(protected) && !defined(private) && !defined(class) // 悪魔払い #ifndef HOGE_H_INCLUDED // 通常のインクルードガード #define HOGE_H_INCLUDED // ヘッダーの内容を書く #endif // HOGE_H_INCLUDED #endif // 悪魔払い |
怪しいマクロを定義しているヤツにはインクルードさせてやらねーよ!ということですね。
ただし開発業務は進まなくなります。
まとめ
- アクセスレベルは簡単に書き換えられる
- この知識との上手な付き合い方は単に使わないこと
- 防衛策はPimplイディオム
おまけ
このprivateを再定義するアプローチは厳密にはc++のルールに違反している(c++のキーワードを再定義している)ので、本来何がおこっても不思議ではありません。たまたま無効化できているといったところです。
ちなみにある条件の下では、c++のルールに違反せずprivateメンバにアクセスする方法もあります。