C A L E N D A R
プロフィール
ADMIN:Kuar メール kuar☆ mail.goo.ne.jp(メッセ対応) スカイプ kuar_s HP http://sora-blue.net/~kuar/index.html mixi http://mixi.jp/show_profile.pl?id=10917408
最新記事
(08/07)
(02/21)
(01/04)
(12/23)
(04/11)
カウンター
ブログ内検索
アーカイブ
|
[C++]あたかもメンバの別名のように振る舞う
あまりこういうことには出会わないとは思うが稀にメンバの名前を変えたいとか振る舞い方を変えたいとかあったりする。
例えばWindowsでのRECT構造体。 struct RECT{ int left,top,right,bottom; }; こいつをちょっと不便だから struct Rect{ int x,y,width,height; }; にしたいと考える。 このままRectを拡張してしまえばいいじゃないかと思う人は話はここまでである。 しかしまあ、このまま拡張しても不便だから。特にRECTの参照渡しをする機会が多いのでその都度 RECT rect = Rect.RECT(); hoge(&rect); とするのも面倒なわけである。 そのままダイレクトに引数に入れるために継承を行うとする。 struct Rect:public RECT{ }; メンバをどうするかである。プロパティとしてはx,y,width,heightとして扱いたい。 xとyに関しては少々不細工であってもleftとrightのポインタを持っておけばなんとかなりそうでもない。 struct Rect:public RECT{ Rect():x(&left),y(&top){} int* x,y; }; widthやheightはそうはいかない。widthはright-left、heightはbottom-topという式になる。 struct Rect:public RECT{ Rect():x(&left),y(&top){} int width()const{return right-left;} int width(int newWidth){return right = left + newWidth;} int height()const{return bottom-top;} int height(int newHeight){return bottom = top + newHeight;} int* x,y; }; 形はどうであれこれでひとまずは、できたかのように思える。 しかしもっと自然に振舞いたいと思うわけである。 *rect.x = 1; rect.width(3); これを rect.x = 1; rect.width = 3; などど記述できればまさにメンバの名前を変えたように振る舞っているといえよう。
ということで本題である。
プリミティブ型はoverrideできないので一旦クラスにしてやる。 そして代入演算子をoverrideする。 template<class T> class Dummy{ public: Dummy(T* _t):t(_t){} T operator=(const T& _t){return *t=t;} private: T* t; }; こうしてやれば直に代入演算ができる。 struct Rect:public RECT{ Rect():x(&left),y(&top){} Dummy }; rect.x = 3; 右辺値参照ではDummy型になって不便なのでキャスト演算子と左辺値参照の+オペレーターを用意しよう。 template<class T> class Dummy{ public: Dummy(T* _t):t(_t){} T operator=(const T& _t){return (*t = _t);} T operator +()const{return *t;} T operator -()const{return -*t;} T operator+(T _t)const{ return (*t) + _t;} operator T()const{ return *t;} private: T* t; }; これでちょっと違和感はあるもののprintf("%d\n",+rect.x);などで記述できる。 もっともキャストしてやってもいい。+を打つほうが楽だが。 同様にしてwidthとheight用のクラスを用意する。 template<class T> class SubDummy{ public: SubDummy(const T* _t1,T* _t2):t1(_t1),t2(_t2){} T operator=(const T& _t)const{return *t2 = _t + *t1;} T operator +()const{return *t2 - *t1;} T operator -()const{return -(*t2 - *t1);} T operator+(T _t)const{return *t2 - *t1;} operator T()const{return *t2 - *t1;} private: const T* t1; T* t2; }; ついでにostream用にoverrideもしておくとstd::coutできるようになったりして便利。 template<typename T> inline std::ostream& operator<<(std::ostream& os, const Dummy<T>& dummy){ return os << +dummy; } template<typename T> inline std::ostream& operator<<(std::ostream& os, const SubDummy<T>& dummy){ return os << +dummy; } できたRectがこいつ。 class Rect : public RECT{ public: Rect(int _left,int _top,int _right,int _bottom):x(&left),y(&top),width(&left,&right),height(&top,&bottom){ left = _left; top = _top; right = _right; bottom = _bottom; } Dummy<int> x,y; SubDummy<int> width,height; }; int main(void){ Rect rect(1,2,3,4); rect.left = 3; rect.width = 5; rect.top = 6; printf("%d,%d,%d\n",+rect.x,+rect.width,rect.right); return 0; } 本来のleftやtopにアクセスしても大丈夫であるし、widthを変更してもleftやtopに変更がなされる。 出力や代入で右辺値にくる場合は+かキャストが必要になるのが少々気になるがほぼ完全にプロパティを偽っていると言えよう。 PR
・C O M M E N T
TRACKBACK
この記事のURL▽ この記事のトラックバックURL▽
|
CopyRight (c) のなちす All Right Reserevd. |