2

初めまして、タイトル失礼します。聞きたいことを 1 つのフレーズにまとめることができませんでした :(

私はこの投稿を読んでいましたが、どういうわけか関数ポインターについて考えさせられました。具体的には、クラスメンバー関数を関数パラメーターとして渡し、そのポインターをその関数内の既存のオブジェクトで使用するのがなぜ「悪い」(または、少なくともめったに見られない)のか疑問に思っていました。

T 型の変数を 1 つ格納し、この変数への const 参照を取得するメソッドを提供するテンプレート クラス "Container" があるとします。

template<class T>
class Container {
public:
    Container(T anObject) {
        m_data = anObject;
    }
    const T& getData() const {
        return m_data;
    }
private:
    T m_data;
};

ここで、m_data で T のメンバー関数を実行できるようにしたいと考えていますが、getData() を非 const にしたくはありません。これは、返された参照を使用して他のあらゆる種類のいたずらを可能にするためです。私の解決策は、T のメンバー関数への関数ポインターをパラメーターとして受け取り、m_data で実行する新しいパブリック関数、modifyData(...) を Container に追加することです。そのようです:

// ...
void modifyData( void(typename T::*funcptr)(void) ) {
    (m_data.*fptr)();
}
// ...

そのままでは、T がポインターの場合、これはクラッシュして書き込みます。テストのために、これに対処するための専用のテンプレートを作成しましたContainer<T*>が、もっとエレガントな方法があると確信しています。

非常に解釈された例は、これが意図したとおりに機能しているように見えることを示しています。

// example class to be used with Container
class Data {
public:
    Data() {m_count = 0; }
    void incrementCount() { m_count++; }
    int getCount() const { return m_count; }
private:
    int m_count;
};

// ... in main.cpp:
Data dat;
Container<Data*> DCont(dat);
std::cout << cl.getData()->getCount() << std::endl; // outputs 0
DCont.modifyData<Data>(&Data::incrementCount);
std::cout << cl.getData()->getCount() << std::endl; // outputs 1

// compiler catches this:
// DCont.modifyData<SomeOtherClass>(&Data::incrementCount); 
// this probably does something bad:
// DCont.modifyData<SomeOtherClass>(&SomeOtherClass::someFunc); 

さて、本能的には、これは恐ろしくねじれた方法のように思えますが、このように機能するコードは見たことがありません。しかし、私の質問は、このようなものが悪いのはパフォーマンス/セキュリティ上の理由ですか、それとも悪い習慣と見なされているだけですか? それが「単なる」悪い習慣である場合、それはなぜですか?

私が考えることができる明らかな制限は、 // DCont.modifyData(&SomeOtherClass::someFunc); のようなものです。おそらく実行時にクラッシュしますが、incrementData() で U の型を T と照合することで対処できると思います。また、そのままでは、modifyData は void (*)() 関数のみを受け入れますが、これはおそらく可変個引数テンプレートで対処できます。

この例は明らかに非常に解釈されており、あまりうまく実装されていませんが、私が話していることを説明するには十分だと思います (願っていますか?)。

ありがとう!

編集:質問が何であるかについて、いくつかの混乱があるようです。基本的に、これは私が話しているシナリオです: コンテナに格納しようとしているいくつかのライブラリからのクラスの束と、特定のコンテナを生成する別の関数があります。ここで、ユーザーがこれらのコンテナー内のオブジェクトで既存のメンバー関数を呼び出せるようにする必要がありますが、実際のオブジェクトを変更することはできません (getter で非 const 参照を返す場合など)。実際の実装では、おそらくある種の可変個引数テンプレートを使用して役立つでしょうが、サンプル コードを投稿する前に、もう少し考えてみる必要があります。

つまり、コンテナー メンバーへのユーザー アクセスを、そのメンバーのメンバー関数のみに制限したいと考えています。これを行う簡単な方法はありますか、またはこの方法は意図したとおりに機能しませんか?

4

1 に答える 1

1

私はあなたのアーキテクチャに問題はありません-私はそれを悪い習慣とは見ていません。私には、データを保護するのは非常に面倒な方法のように思われ、ユーザーがvoid関数を使用して含まれているデータを変更できるという点で、あまり役に立ちません。実際には、変更できるものとできないものに関する契約ではありません。

この構成がめったに見られない理由は、コンテナクラスの要件と目標が異常であるためだと思います。

于 2012-08-14T15:26:38.243 に答える