web-dev-qa-db-ja.com

C ++基本クラスコンストラクターを使用していますか?

テンプレートを操作している間、コピー/貼り付け操作を減らすために、オブジェクト作成のために継承されたクラスからアクセス可能な基本クラスコンストラクターを作成する必要が生じました。関数の場合と同じ方法でusingキーワードを使用してこれを行うことを考えていましたが、うまくいきません。

class A
{
public: 
    A(int val) {}
};

class B : public A
{
};

class C : public A
{
public:
    C(const string &val) {}
};

class D : public A
{
public:
    D(const string &val) {}
    using A::A;              // g++ error: A::A names constructor
};

void main()
{
    B b(10);                // Ok.   (A::A constructor is not overlapped)
    C c(10);                // error: no matching function to call to 'C::C(int)'
}

だから私の質問:継承されたクラスの新しいコンストラクタが宣言された後にベースクラスコンストラクタをインポートする方法はありますか?

または、新しいコンストラクターを宣言し、初期化子リストから基本コンストラクターを呼び出す方法は1つだけですか?

49
minyor

初期化を優先する:

class C : public A
{
public:
    C(const string &val) : A(anInt) {}
};

C++ 11では、継承コンストラクターを使用できます(例のDに見られる構文があります)。

更新:継承コンストラクターは、バージョン4.8からGCCで使用可能です。


初期化が魅力的でない場合(実際の場合の可能性の数など)、いくつかのTMP構造に対してこのアプローチを好むかもしれません:

class A
{
public: 
    A() {}
    virtual ~A() {}
    void init(int) { std::cout << "A\n"; }
};

class B : public A
{
public:
    B() : A() {}
    void init(int) { std::cout << "B\n"; }
};

class C : public A
{
public:
    C() : A() {}
    void init(int) { std::cout << "C\n"; }
};

class D : public A
{
public:
    D() : A() {}
    using A::init;
    void init(const std::string& s) { std::cout << "D -> " << s << "\n"; }
};

int main()
{
    B b; b.init(10);
    C c; c.init(10);
    D d; d.init(10); d.init("a");

    return 0;
}
37
justin

はい、C++ 11以降:

struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// The set of inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()

// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};

詳細については、 http://en.cppreference.com/w/cpp/language/using_declaration を参照してください

55
Sergei

いいえ、そうではありません。基本クラスを初期化する通常の方法は、初期化リストにあります。

class A
{
public: 
    A(int val) {}
};

class B : public A
{
public:
  B( int v) : A( v )
  {
  }
};


void main()
{
    B b(10);
}
8
BЈовић

各派生クラスでコンストラクターを宣言し、初期化子リストから基本クラスコンストラクターを呼び出す必要があります。

class D : public A
{
public:
    D(const string &val) : A(0) {}
    D( int val ) : A( val ) {}
};

D variable1( "Hello" );
D variable2( 10 );

C++ 11では、Dの宣言に使用するA :: A構文を使用できますが、C++ 11機能は現在すべてのコンパイラでサポートされているわけではないため、これまでは古いC++メソッドを使用することをお勧めしますこの機能は、コードを使用するすべてのコンパイラに実装されています。

4
obmarg

ルールを呼び出すスーパークラスコンストラクター についての良い議論です。オブジェクトを適切に形成するために、派生クラスコンストラクターの前に基本クラスコンストラクターを常に呼び出す必要があります。このフォームが使用される理由です

  B( int v) : A( v )
  {
  }
1
jbat100