12

次のように、純粋な仮想親クラスで関数の子実装を呼び出す必要があります。

class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() = 0;
    parent() 
    {
        Read();
        Process();
    }
}
class child : public parent
{
  public:
    virtual void Process() { //process stuff }
    child() : parent() { }
}

int main()
{
   child c;
}

これは機能するはずですが、リンクされていないエラーが発生します:/ これは VC++ 2k3 を使用しています

それともうまくいかないのですか、私は間違っていますか?

4

7 に答える 7

19

次の記事のタイトルはすべてを物語っています:構築中または破壊中に仮想関数を呼び出さないでください。

于 2008-10-24T00:03:47.907 に答える
4

または、オブジェクトを作成するためのファクトリ メソッドを作成し、コンストラクタをプライベートにします。ファクトリ メソッドは、構築後にオブジェクトを初期化できます。

于 2008-10-24T00:22:10.897 に答える
2

一般的には機能しますが、純粋な仮想基本クラスのコンストラクター内の呼び出しでは機能しません。基本クラスが構築された時点では、サブクラスのオーバーライドは存在しないため、呼び出すことはできません。オブジェクト全体が構築されたらそれを呼び出す限り、それは機能するはずです。

于 2008-10-24T00:01:18.787 に答える
2

これは、呼び出しがコンストラクター内にあるためです。派生クラスはコンストラクターが完了するまで有効ではないため、コンパイラーはこれを正しく実行します。

2つの解決策があります:

  1. 派生クラスのコンストラクターでProcess()を呼び出します
  2. 次の例のように、Processの空白の関数本体を定義します。
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}
于 2008-10-24T00:02:58.673 に答える
2

もう一歩で、次のような関数を導入することができます

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}
于 2008-10-24T09:27:39.593 に答える
1

表面的な問題は、まだ知られていない仮想関数を呼び出すことです (オブジェクトは親から子へと構築されるため、vtables も同様です)。あなたのコンパイラはそれについてあなたに警告しました。

私が見る限り、本質的な問題は、継承によって機能を再利用しようとすることですこれはほとんどの場合、悪い考えです。いわば設計上の問題です:)

基本的に、テンプレート メソッド パターンをインスタンス化して、whenから分離しようとします。最初にデータを (何らかの方法で) 読み取り、次にそれを (何らかの方法で) 処理します。

これはおそらく集計でよりうまく機能します。適切なタイミングで呼び出されるように、Processing 関数を Template メソッドに与えます。おそらく、読み取り機能についても同じことができます。

集計は、次の 2 つの方法で実行できます。

  1. 仮想関数の使用 (つまり、ランタイム バインディング)
  2. テンプレートの使用 (つまり、コンパイル時のバインディング)

例 1: ランタイム バインディング

class Data {};
class IReader    { public: virtual Data read()            = 0; };
class IProcessor { public: virtual void process( Data& d) = 0; };

class ReadNProcess {
public:
    ReadNProcess( IReader& reader, IProcessor processor ){
       processor.process( reader.read() );
    }
};

例 2: コンパイル時バインディング

template< typename Reader, typename Writer > // definitely could use concepts here :)
class ReadNProcess {
public:
     ReadNProcess( Reader& r, Processor& p ) {
         p.process( r.read() );
     }
};
于 2008-10-24T09:48:59.317 に答える
0

オブジェクトが完全に構築された後、仮想メソッドを呼び出すオブジェクト内にラップする必要があります。

class parent
{
  public:
    void Read() { /*read stuff*/ }
    virtual void Process() = 0;
    parent()
    {
        Read();
    }
};

class child: public parent
{
  public:
    virtual void Process() { /*process stuff*/ }
    child() : parent() { }
};

template<typename T>
class Processor
{
    public:
        Processor()
            :processorObj() // Pass on any args here
        {
            processorObj.Process();
        }
    private:
        T   processorObj;

};




int main()
{
   Processor<child> c;
}
于 2008-10-24T00:28:11.507 に答える