2012-02-28 8 views
1

は基本的に私は以下のようなコードの多くを書いて、今日自分自身を発見した:"Redirect"クラスメンバー関数?

#define VAL_1 0 
#define VAL_2 1 

class A { 

public: 
    void memberA(); 
    void memberB(); 

    ... 

    void write(uin32_t address); 

} 

void 
A:: 
memberA() { 

    this->write(VAL_1); 

} 

void 
A:: 
memberB() { 

    this->write(VAL_2); 

} 

... 

だから、基本的に、私は実際には異なる引数で同じ機能writeを呼び出して行い、いくつかのタスクのための「かわいい」の名前memberAmemberBを持っています。値VAL_0VAL_1は必ずしも自分のクラスを使用してコードすることは知られていません。 writeがある時点で公開されている可能性もありますが、実装の詳細はmemberAまたはmemberBのどちらでもありません。

基本的には今度は同じコード行this->write(...)を何度も繰り返しています。私はこの手順をバイパスし、それぞれの書き込みをすぐに呼び出すソリューションを探しています。おそらく一致する引数を指定して、多少の基本クラスからC++コンストラクタのように関数の引数の上渡しの種類:

#define VAL_1 0 
#define VAL_2 1 

class A { 

public: 
    bool memberA() : write(VAL_1); 
    bool memberB() : write(VAL_2); 

    ... 

    bool write(uin32_t address); 

} 

私はBoost.Bindで何かまたはいくつかの巧妙なテンプレートコードがあるかもしれないかどうかを思ったんだけど私はこの種のことを達成できますか?あなたはクラス定義にインラインであなたのmemberX関数を作り、そしてあなたが冗長this参照を避ける場合は、あなたが書くためにあまりにも多くの余分持っていない場合は

おかげで、

FROB

答えて

2
:さらに

#define F(l, n) bool l() { return write(n); } 
F(memberA, VAL_1) 
F(memberB, VAL_2) 
#undef F 

、あなたはプリプロセッサトークンの結合演算子##を使用することができます

あなたが何をしているのかを完全に理解していないと(私はコンストラクタを含む最後の部分について混乱しています)、クライアントで構文を簡単にするのは少し難しいかもしれません。それはあなたが簡単に構文を確立しようとしていることを良いことだが、あなたはまた、monolithismの危険を回避する必要が

class A { 
public: 
    enum Value {val1, val2, val3, val4, etc}; 
    bool write(Value val); 
}; 

:方法については、単に

...。モノリシッククラスは、オブジェクト指向設計における最も一般的な誤りの1つであると強く信じているものです。 SutterはC++ Coding Standardsとgotw:http://www.gotw.ca/gotw/084.htmで詳しく説明しています。

100のメンバー関数を持つクラスをお持ちの場合は、おそらく約80を超えています。

^しばらくこの声明を考えてください。非常に多くの機能を持つと、クラスの管理がますます困難になる傾向があります。また、他の開発者がクラスにさらに多くの機能を追加し続けることで、設計が決して完結しないようにしています。その結果、開発サイクルごとに成長し、成長していく終わりのないクラスが終わりに見えます。バグ、非効率、パブリックインターフェイスの改定、単体テストの破損の原因となり易く、クラスの一般的な再利用や柔軟性に反する可能性があります。値ごとに別々の関数を渡して、別の関数に渡すことができれば、その領域を危険に冒すことになります。

避けがたいです。構文の冗長性は通常間違いです。残念ながら、C++は場合によってはもっと長い構文を必要とするだけです(C++ 11でもっとうまくいく)。あなたが離れて最適化しようとするべきは論理冗長です。ここでは、さまざまな値を持つ書き込みメソッドの呼び出しには論理的な冗長性はなく、構文上のオーバーヘッドは、書き込みに渡す可能性のある値ごとに異なる関数を呼び出すことにとどまりません。

これらの関数が、さまざまな値を渡す構文を単純化するだけであれば、プロダクション環境にある場合は、クラスのパブリックインターフェイスを非常に多くの機能で拡張していることに気が付く必要があります個別に文書化し、教える必要があります。より多くのことをやろうと努力してください。あなたはずっと楽になると思います。

モノリシズムのこの側面を優先事項として念頭に置いてください。あなたも、これまでのようにのように、非メンバーとしてクラス定義のうち名前付き定数を掲揚するように行くかもしれない:

class A { 
    bool write(uint32_t address); 
}; 

// elsewhere 
static const uint32_t address_val1 = ...; 
static const uint32_t address_val2 = ...; 
static const uint32_t address_val3 = ...; 

は、この設計には何の問題も実際にはありませんと、実際には、それがより望ましいエンジニアリングの特性を持っていますそれはあなたのクラスから完全に切り離されているので、より多くのクラスメンバーを持っているよりも、そのクラスのメンテナンスを容易にし、インターフェイスを教えて文書化が簡単になり、合理的な完了状態になる可能性が高くなります。

+0

さて、私はそれを理解しています。しかし、 'memberA'と' memberB'は子クラスに異なる実装を持っていますので、あなたの解決策でこれらを上書きすることはできません... – FRob

+0

私の提案は、memberAとmemberB関数をまったく持っているのではなく、クライアントがmy_a.write(address_val1)を書かせるだけの目的で、これらの関数を完全に削除するようにします。ところで、あなたは最適化としてこれをやろうとしていますか?その場合、コンパイラがその最適化を適用した後に、memberAとmemberBは通常、オーバーヘッドがゼロになるため、プロセッサ効率の観点からそれらの関数を書くコストは効果的に*ゼロ*になります。これらの関数を書くのが面倒だと分かったら、それは別のものです。しかし、マクロを使って... – stinky472

+0

クラスメソッドは一般的にハックと見なされます。通常のプロダクション環境でコードレビューに合格しないと、プリプロセッサを介して既にこのような1ライナーであるものを省略することができます。 – stinky472

4

ご希望の(間違った)構文:

bool memberA() : write(VAL_1); 

実際の(正しい)構文:

bool memberA() { return write(VAL_1); } 

あなたの反復コードを最小限にしたい場合は、プリプロセッサを使用することができますが:

#define F(l, n) bool member##l() { return write(VAL_##n); } 
F(A, 1) 
F(B, 2) 
#undef F 
+0

ご意見ありがとうございます。それも私が思いついたものですが、私はそこではこれについてよりスマートになる方法があると思っていました。 :/ – FRob