Наследование конструкторов
Почему этот код:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
};
int main(void)
{
B *b = new B(5);
delete b;
}
Результат в этих ошибках:
main.cpp: в функции 'int main ()': main.cpp:13: ошибка: нет подходящей функции для вызова 'B:: B (int)' main.cpp: 8: примечание: кандидаты: B:: B () main.cpp: 8: примечание: B:: B (const B &)
Разве B не должен наследовать конструктор A?
(это использует gcc)
8 ответов
Если ваш компилятор поддерживает стандарт C++11, существует наследование конструктора с использованием using
(каламбур предназначен). Подробнее см. Статью в Википедии C++11. Ты пишешь:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
using A::A;
};
Это все или ничего - вы не можете наследовать только некоторые конструкторы, если вы пишете это, вы наследуете их все. Чтобы наследовать только выбранные, вам нужно написать отдельные конструкторы вручную и вызвать из них базовый конструктор.
Исторически конструкторы не могли быть унаследованы в стандарте C++03. Вам нужно было наследовать их вручную один за другим, вызывая базовую реализацию самостоятельно.
Конструкторы не наследуются. Они вызываются неявно или явно дочерним конструктором.
Компилятор создает конструктор по умолчанию (один без аргументов) и конструктор копирования по умолчанию (один с аргументом, который является ссылкой на тот же тип). Но если вам нужен конструктор, который будет принимать int, вы должны определить его явно.
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
explicit B(int x) : A(x) { }
};
ОБНОВЛЕНИЕ: В C++11 конструкторы могут наследоваться. См. Ответ Сума для деталей.
Это прямо со страницы Бьярна Страуструпа:
Если вы захотите, вы все равно можете выстрелить себе в ногу, унаследовав конструкторы в производном классе, в котором вы определяете новые переменные-члены, нуждающиеся в инициализации:
struct B1 {
B1(int) { }
};
struct D1 : B1 {
using B1::B1; // implicitly declares D1(int)
int x;
};
void test()
{
D1 d(6); // Oops: d.x is not initialized
D1 e; // error: D1 has no default constructor
}
Вы должны явно определить конструктор в B и явно вызвать конструктор для родителя.
B(int x) : A(x) { }
или же
B() : A(5) { }
Как насчет использования функции шаблона для связывания всех конструкторов?
template <class... T> Derived(T... t) : Base(t...) {}
Вот как я это делаю. Я считаю, что это наиболее простой способ, поскольку он просто передает все аргументы конструктору родительского класса.
class Derived : public Parent {
public:
template <typename... Args>
Derived(Args&&... args) : Parent(std::forward<Args>(args)...)
{
}
};
Или, если вы хотите иметь хороший макрос:
#define PARENT_CONSTRUCTOR(DERIVED, PARENT) \
template<typename... Args> \
DERIVED(Args&&... args) : PARENT(std::forward<Args>(args)...)
class Derived : public Parent
{
public:
PARENT_CONSTRUCTOR(Derived, Parent)
{
}
};
Правильный код
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
B(int a):A(a){
}
};
main()
{
B *b = new B(5);
delete b;
}
Ошибка b/c. В классе B нет конструктора параметров, и, во-вторых, в нем должен быть инициализатор базового класса для вызова конструктора конструктора параметров базового класса.
производный класс наследует все члены (поля и методы) базового класса, но производный класс не может наследовать конструктор базового класса, поскольку конструкторы не являются членами класса. Вместо наследования конструкторов производным классом разрешено вызывать только конструктор базового класса.
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
B(int x):A(x);
};
int main(void)
{
B *b = new B(5);
delete b;
}