Использование конструкторов базового класса С++?

Во время работы с шаблонами я столкнулся с необходимостью создания конструкторов базового класса, доступных из унаследованных классов для создания объектов, для уменьшения операций копирования/вставки. Я думал сделать это с помощью ключевого слова 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

Предпочитает инициализацию:

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

В С++ 11 вы можете использовать наследующие конструкторы (у которых есть синтаксис, указанный в вашем примере D).

Обновление: Наследование конструкторов доступно в GCC с версии 4.8.


Если вы не найдете апелляцию инициализации (например, из-за количества возможностей в вашем фактическом случае), вы можете одобрить этот подход для некоторых конструкций 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;
}

Ответ 2

Да, поскольку С++ 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

Ответ 3

Нет, это не так, как это делается. Обычный способ инициализации базового класса находится в списке инициализации:

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

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


void main()
{
    B b(10);
}

Ответ 4

Вам нужно объявить конструкторы в каждом из производных классов, а затем вызвать конструктор базового класса из списка инициализаторов:

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

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

С++ 11 позволяет использовать синтаксис A:: A, который вы используете в своем объявлении D, но функции С++ 11 не поддерживаются всеми компиляторами сейчас, поэтому лучше всего придерживаться старого С++ до тех пор, пока эта функция не будет реализована во всех компиляторах, с которыми будет работать ваш код.

Ответ 5

Вот хорошее обсуждение правил вызова конструктора суперкласса. Вы всегда хотите, чтобы конструктор базового класса вызывался перед конструктором производного класса, чтобы правильно сформировать объект. Вот почему эта форма используется

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