3

コールバック ベースのクラスを作成しています。クライアントが定義したコールバックを呼び出す自由をクライアントに与える必要があります。たとえば、クラス Base があります。

class Base
{
...
 public:
    virtual void OnMsgReceived(const char *msg, char *&response);
    virtual void OnMsgReceived(const char *msg, string &response);
};

クライアントはどちらか一方を実装する必要がありますが、2 つではありません

オブジェクトの構築インスタンス化中にはできないことはわかっていますが、オブジェクトがインスタンス化されたら、これらの仮想関数のどれが実装されているかを確認する方法はありますか? ありがとう。

4

5 に答える 5

0

ばかげたアプローチ:基本クラスで一方から他方にディスパッチします。ユーザーがそれらの少なくとも1つをオーバーライドしていない限り、簡単に検出できるスタックオーバーフローが発生します。

void Base::OnMsgCallback(const char *msg, char*& response) {
   std::string resp;
   OnMsgCallback(msg,resp);
   response = new char[resp.size()+1]();
   std::copy(resp.begin(), resp.end(), response);
}
void Base::OnMsgCallback(const char *msg, std::string& response) {
   char *resp;
   OnMsgCallback(msg,resp);
   response = resp;
   delete [] resp;
}

しかし、これはひどいハックであり、お気づきかもしれませんが、このchar*バージョンではリソースを手動で処理する必要があり、エラーが発生しやすくなっています。への参照を渡す単一のインターフェースを定義することで、はるかに優れていますstd::string(または、戻り型が、std::stringコントラクト(inoutまたはjust outパラメーターですか?)とコード(呼び出し前にを作成する必要はありません)を単純化します。折り返し電話。responsestd::string

于 2012-11-10T04:31:34.013 に答える
0

iammilindの応答に何かを追加したいと思います:

クラスで純粋仮想関数を使用する場合、そのクラスを抽象化するため、インスタンス化することはできません。

Aが抽象クラスの場合

class A
{
  public:
  //
  virtual void foo() = 0;
  //
}

あなたは書くことができません

A myA

これに関する優れたリソースの1つは、いつものように、Parashift C ++FAQWebサイトです。

于 2012-11-10T04:24:25.333 に答える
0

virtual純粋な技術のない C++ では、virtual関数がクラスによって実装されているかどうかを実行時に知る方法はありません。

両方の関数を純粋仮想関数として定義し、クライアントに両方を実装させます。必要に応じて、純粋仮想関数の本体を引き続き使用できBaseます。

クライアントはいずれか 1 つを実装する必要がありますが、2 つを実装することはできません。

両方のバージョンが本当に必要であると仮定すると、上記の要件を持つ必要はないと思います。

コールバックを処理するときに正しいものを呼び出すために、彼が実装したものをどのように知ることができますか?

適切なオブジェクトを参照/ポインターに割り当てれば、Baseこれについて心配する必要はありません。コンパイラは、その汚い仕事をしてくれます。

補足として、 CRTP手法を調べることもできます。派生クラスは、コンパイルを渡すために特定のメソッドを実装する必要があります。ただし、それは機能ほど柔軟ではありませんvirtual

于 2012-11-10T04:15:23.590 に答える
0

その設計は非常に多くの理由で悪いですが、とにかくあなたのやり方をする方法があります:

class Base
{
public:
    virtual void OnMsgReceived(const char *msg, char *&response)
    {
        response = (char*)"OMG! nothing derived"; // or throw if you want
    }

    virtual void OnMsgReceived(const char *msg, string &response)
    {
        char *ptr_to_dest = 0;
        OnMsgReceived(msg, ptr_to_dest);
        response = ptr_to_dest;
    }
};

常にstringを使用して呼び出します。どちらが実行されたかを確認する必要はありません。

これは、実装する内容に応じて次のようになります。

  • charバージョンのみを実装-> 呼び出されて文字列に変換されます
  • 文字列バージョンのみを実装-> 直接呼び出されます
  • 両方のバージョンを実装->文字列のみが呼び出されます
  • 何も実装しない-> デフォルトのメッセージ (またはスローした場合は例外) を取得します。
于 2012-11-10T11:49:10.837 に答える
0

どの関数がオーバーライドされたかを把握するのは簡単ではありません - たとえできたとしても、それは開発者が従うのが非常に難しい設計でもあります:クライアントはいずれか 1 つを実装する必要がありますが、2 つではありません。気に入らないかもしれません!

あなたのデザインに基づいた別の方法を提案します:

あなたのフレームワーク

class Base0
{
public:
    // other basic members

};

template<class T>
class Base : public Base0
{
    virtual void OnMsgReceived(const char *msg, T &response) = 0;
};


typedef Base<char*> BaseChar;

typedef Base<string&> BaseString;



void run(Base0* pBase)
{
    const char* msg = getmsg();
    BaseChar* p = dynamic_cast<BaseChar*>(pBase);
    if(p != NULL)
    {
        char* response; // 
        p->OnMsgReceived(msg, response)
        return;
    }

    BaseString* p2 = dynamic_cast<BaseString*>(pBase);
    if(p2 != NULL)
    {
        string response; // 
        p2->OnMsgReceived(msg, response)
        return;
    }

}

クライアントコード

class Derived: public BaseChar
{
public:
    virtual void OnMsgReceived(const char *msg, char* &response)
    {
        // do sth
    }       
};

フレームワークのユーザーは、BaseChar または BaseString のいずれかを実装する必要があります。その後、すべてが機能します。

于 2012-11-10T04:38:21.793 に答える