1

私の知る限り、C++ ではコンストラクターを継承できません。しかし、ベースをインスタンス化するのと同じ方法で、継承されたクラスをインスタンス化できるように見えることが必要になる場合があります。

struct Base {
  int i;
  int const j;
  Base(int i, int j) : i(i), j(j) {}
};

// option 1)
struct Derived1 : Base {
  Derived1(int i, int j) : Base(i,j) {}
};
Base* baseFactory() {
  return new Derived1(42,47);
}

// option 2)
struct Derived2 : Base {
};
Base* baseFactory() {
  Base* b = new Derived2();
  b->i = 42;
  b->j = 47; // broken!
  // alternative could be to implement Base::operator=
  return b;
}

派生クラスは、基本クラスがない場合、デフォルトで構築される可能性があることに注意してください。

オプション 1 は通常行われていることだと思いますが、新しいことを何も表現せずにコードを入力しています。オプション 2constでは、すべてが代入可能でなければならないため、正確性が損なわれます (また、参照をメンバーとして使用できなくなります)。

これを回避する良い方法はありますか?

編集: C++11 は素晴らしいですが、残念ながら C++03 ソリューションが必要です。

4

4 に答える 4

3

オプション1はC++03の慣用的な方法であり、より多くの入力が必要ですが、それが言語のやり方です。オプション2は同等に近いものではなく、デフォルトコンストラクターがないため初期化できDerived2ません。また、暗黙的に宣言されたデフォルトコンストラクターBaseの定義にはそれが必要です。Derived2

しかし、言語の技術的な難しさを超えて、構築2フェーズ構築と交換することは決して良い考えではなく、同時にDerived2動的に割り当てられたオブジェクトの使用を強制します。

于 2011-10-29T12:24:21.070 に答える
2

別のアプローチがあります。

// option 3)
struct Derived3 : Base {
  Derived3(const Base &b) : Base(b) {}
};
Base* baseFactory3() {
    return new Derived3(Base(42,47));
}

完全な Base オブジェクトの構築に費用がかかるか、外部リソースが必要な場合、これは良い考えではないかもしれません。その場合、複数の Base コンストラクターの代わりに、複数の BaseArguments コンストラクターと、BaseArguments を受け取る 1 つの Base コンストラクターを持つように、Base のコンストラクター引数を運ぶ軽量オブジェクトを作成できます。しかし、ほとんどの状況でそのスタイルが良いと考える人はあまりいないと思います。

于 2011-10-29T13:33:48.403 に答える
1

これは、ビルダーパターンのバリエーションであり、常に役立つと思っていましたが、実際に使用する機会はありませんでした。コンストラクターパターンと呼べるかもしれません。:P

また、特定の順序で引数を指定する必要がないなど、他のいくつかの利点もあります。関心のあるものだけを、必要な順序で指定するだけです。

これは、クラスにさまざまなパラメーターを持つコンストラクターがたくさんある場合にのみ正当化されると思います。そうでなければ、それはただの迷惑です。

class Person
{
  public:
    class Constructor;
};

class Person::Constructor
{
  public:
    Constructor& name(const std::string&);
    Constructor& age(int);
    Person* make();
};

Person* pers = Person::Constructor()
    .name("Bob Marley").make();


class Employee : public Person
{
  public:
    class Constructor;
};

class Employee::Constructor : public Person::Constructor
{
  public:
    Constructor& salary(double);
    Employee* make();
};

Employee* emp = Employee::Constructor()
    .name("Emilly Smith").age(23).make();

ただし、これは、クラスに多数のパラメーターを持つコンストラクターが多数あり、それらに複数のオーバーロードを書き込む必要がない場合にのみ正当化されます。そうでなければ、これは実際の利益なしに複雑さを増すだけです。

私はハンの提案した解決策が好きではないと言いました。これは、(1)子クラス内の多数のコンストラクターを(再)宣言する必要性を、ファクトリクラス内に同じ数の関数を配置する必要性に移動しているためです。(2)それはハッキーであり、意図は明確ではありません。(3)これを依存性注入の違反と見なすことができます。

于 2011-11-03T16:27:05.200 に答える
1

C++11 は、継承されたコンストラクターをサポートしています。

http://en.wikipedia.org/wiki/C%2B%2B11

ただし、現在 C++11 のサブセットをサポートしているすべてのコンパイラがすべての機能をサポートしているわけではありません。

Microsoft Visual C++ 2010 はいくつかの新しい C++0x 機能をサポートしていますが、継承されたコンストラクターはサポートしていません。リストは次のとおりです。言語機能-in-vc10-the-table.aspx

GCC はより多くの新機能をサポートしていますが、継承されたコンストラクターはサポートしていません。http://gcc.gnu.org/projects/cxx0x.htmlを参照

GCC が C++0x 機能でコンパイルできるようにするには-std=c++0x-std=gnu++0xコンパイル パラメータを追加する必要があります。Visual C++ 2010 では、これらが既定で有効になっています。

あなたはただ待つ必要があります:)

以前のバージョンの標準には明確な解決策はありません。このため、以前のバージョンではできなかったため、C++11 で導入されました。したがって、できることは、コンストラクターをコピーして基本コンストラクターを呼び出すことだけです。

于 2011-10-29T10:10:25.460 に答える