Использование конструкторов базового класса в наследнике
Пытаюсь использовать копирующий конструктор базового класса в производном:
#include <vector>
struct Base {
Base() noexcept {}
Base(const Base&) noexcept {}
};
struct Derived : Base {
using Base::Base;
};
int main() {
std::vector<Derived> vec = {Base{}, Base{}};
}
Однако получаю ошибку:
error: could not convert '{Base(), Base()}' from '<brace-enclosed initializer list>' to 'std::vector<Derived>'
13 | std::vector<Derived> vec = {Base{}, Base{}};
| ^
| |
| <brace-enclosed initializer list>
Разве using Base::Base; не добавило Derived(const Base&) noexcept { } в Derived? Если нет, то что произошло?
Ответы (2 шт):
Действительно, using Base<T>::Base; не добавило Derived(const Base&) noexcept { } в Derived. Вместо этого для Derived при необходимости (неявно) создаются свои конструкторы копирования/ перемещения.
При наследовании, объявление using вводит имя из базового класса в область видимости производного класса, а не создает свои экземпляры переменных или функций.
Это - создать синоним для данных или функции, а не создать функцию с таким же именем в классе-наследнике.
Т.е. вы получаете доступ к членам класса Base через имя объекта класса Derived. Но копии не создаются. Вот в коде сравните размер
struct Base
{
int a;
void foo(int){}
};
struct Derived : Base
{
using Base::Base;
};
int main()
{
Base b{};
Derived d{};
d.a = 1;
cout << " Размер Base = " << sizeof(b) << ", размер Derived = " << sizeof(d) << endl;
}
В данном примере Derived::foo() - это синоним Base::foo(), а не копия функции с таким же именем в Derived. Также Derived::a - это синоним Base::a. Чаще всего, т.к. члены класса-родителя и так доступны к использованию в классе-наследнике, то особого смысла в использовании using нет.
Но это используется при выборе функции для запуска. Например:
struct A
{
void f(char) { cout << "In A::f()\n"; }
};
struct B : A
{
using A::f; // A::f(char) теперь видится как B::f(char)
void f(int)
{
cout << "In B::f()\n";
// Если есть using, то вызовется A::f(char)
// Если нет using, то рекурсивно вызовется B::f(int) - `c` автоматически приведется к int
f('c');
}
};
int main()
{
B b;
b.f('a');
}