7

私はこのようになりたい基本クラスを持っています:

class B
{
    // should look like: int I() { return someConst; }
    virtual int I() = 0;
    public B() { something(I()); }
}

重要なのは、派生クラスを強制的にオーバーライドIし、各オブジェクトが構築されるときに強制的に呼び出されるようにすることです。これはいくつかの簿記を行うために使用され、どのタイプのオブジェクトが構築されているかを知る必要があります(ただし、それ以外の場合は、現在のオブジェクトを基本クラスとして扱います)。

C ++ではコンストラクターから抽象仮想関数を呼び出せないため、これは機能しません。

同じ効果を得る方法はありますか?


このリンクに基づくと、答えは私が欲しいものを手に入れる方法がないということのように思われます。しかしそれが言うことは:

簡単な答えは:いいえ。基本クラスは、それがどのクラスから派生したかについては何も知りません。それも良いことです。[...]つまり、コンストラクターDerived1 :: Derived1が開始するまで、オブジェクトは正式にはDerived1のインスタンスにはなりません。

しかし、私の場合、それが何であるかを知りたくはありません、それがどうなるを知りたくありません。実際、ユーザーが(事後に)クラスにマップできる限り、何が返されるかは気にしません。だから私はリターンポインタのようなものを使ってそれを回避することさえできた。

(今、そのリンクを読むことに戻ります)

4

4 に答える 4

8

コンストラクターから仮想メソッドを呼び出すことはできません(より正確には、それらを呼び出すことはできますが、現在構築されているクラスからメンバー関数を呼び出すことになります)。問題は、派生オブジェクトが呼び出されないことです。その瞬間にはまだ存在しています。それについてできることはほとんどありません。コンストラクターから仮想メソッドを多態的に呼び出すことは、単に問題外です。

設計を再考する必要があります。たとえば、定数を引数としてコンストラクターに渡します。

class B
{
public:
    explicit B(int i)
    {
        something(i);
    }
};

詳細については、 C++に関するよくある質問を参照してください。構築中に仮想関数を本当に呼び出したい場合は、こちらをお読みください

于 2009-09-21T06:48:29.690 に答える
1

おそらく、派生型ごとに静的ファクトリメソッドを使用しますか?これは、.NETでエキゾチックなオブジェクト(非常に具体的な初期化要件を持つオブジェクト)を構築する通常の方法です。

class Base
{
  protected Base(int i)
  {
    // do stuff with i
  }
}

class Derived : public Base
{
  private Derived(int i)
    : Base(i)
  {
  }

  public Derived Create()
  {
    return new Derived(someConstantForThisDerivedType);
  }
}

特定のメソッドの動作を確認することはできず、(他の誰かがすでに指摘しているように)派生コンストラクターはまだ呼び出されていないため、基本コンストラクターで仮想メソッドを呼び出すことは一般的に眉をひそめます。

于 2009-09-21T06:58:04.510 に答える
0

基本クラスコンストラクターの実行時に派生クラスがまだ存在しないため、これは機能しません。

class Base
{
public:
    Base()
    {
        // Will call Base::I and not Derived::I because
        // Derived does not yet exist.
        something(I());
    }

    virtual ~Base() = 0
    {
    }

    virtual int I() const = 0;
};

class Derived : public Base
{
public:
    Derived()
     : Base()
    {
    }

    virtual ~Derived()
    {
    }

    virtual int I() const
    {
        return 42;
    }
};

代わりに、基本クラスのコンストラクターに引数を追加できます。

class Base
{
public:
    explicit Base(int i)
    {
        something(i);
    }

    virtual ~Base() = 0
    {
    }
};

class Derived : public Base
{
public:
    Derived()
     : Base(42)
    {
    }

    virtual ~Derived()
    {
    }
};

または、OOPが本当に好きな場合は、いくつかの追加クラスを作成することもできます。

class Base
{
public:
    class BaseConstructorArgs
    {
    public:
        virtual ~BaseConstructorArgs() = 0
        {
        }

        virtual int I() const = 0;
    };

    explicit Base(const BaseConstructorArgs& args)
    {
        something(args.I());
    }

    virtual ~Base() = 0
    {
    }
};

class Derived : public Base
{
public:
    class DerivedConstructorArgs : public BaseConstructorArgs
    {
    public:
        virtual ~DerivedConstructorArgs()
        {
        }

        virtual int I() const
        {
            return 42;
        }
    };

    Derived()
     : Base(DerivedConstructorArgs())
    {
    }

    virtual ~Derived()
    {
    }
};
于 2009-09-21T07:11:03.110 に答える
0

必要なのは二相構造です。ユニバーサルプログラマーの治療法を使用する:間接参照の別のレイヤーを追加します。

于 2009-09-21T08:34:37.167 に答える