Наследование конструкторов копирования и перемещения
Как происходит наследование конструкторов копирования и перемещения?
class Parent {
public:
Parent() = default;
Parent(const Parent& other) {
cout << "Копирования" << endl;
}
Parent(Parent&& other) {
cout << "Перемещения" << endl;
}
};
class Child : public Parent {
public:
};
int main() {
Parent p;
Child c;
Parent p1(c);
Child c1(c);
Child c2(move(c));
}
Вывод:
Копирования
Копирования
Перемещения
Почему этот код работает без using Parent::Parent? Ведь конструкторы не наследуются.
class Parent {
public:
Parent() = default;
Parent(const Parent& other) {
cout << "Копирования" << endl;
}
Parent(Parent&& other) {
cout << "Перемещения" << endl;
}
};
class Child : public Parent {
public:
using Parent::Parent;
Child(const Child& other) {
cout << "Детский Копирования" << endl;
}
};
int main() {
Parent p;
Child c;
Parent p1(c);
Child c1(c);
Child c2(move(c));
}
Вывод:
Копирования
Детский Копирования
Детский Копирования
Почему не унаследовался конструктор перемещения? Я ведь не переопределил его внутри Child.
Также хочу отметить, что подобное поведение не относится к другим конструкторам, они ведут себя очевидно.
Ответы (1 шт):
Конструкторы копирования/перемещения и операторы присваивания не обладают свойством универсальности для наследуемого класса. Например, конструктор наследуемого класса сначала вызывает конструктор базового, затем инициализируются все новые элементы нового класса. И наследование для этих функций не предусмотрено. Так как у этих классов разное количество личных элементов, не говоря уже о том, что базовых классов тоже может быть много.
При отсутствии декларации конструкторов в классе создаются эти элементы компилятором по-умолчанию. А при декларации например одного конструктора копирования, конструктор перемещения по-умолчанию компилятором не создаётся. И программист должен сам написать все эти функции.
В первом примере :
class Child : public Parent {
public:
};
сначала вызывается конструктор предка Parent затем инициализируются личные поля класса Child. И фактически это выглядит как такое объявление :
class Child : public Parent {
public:
Child() : Parent() {}
Child(Child const & x) : Parent ( x ) {}
Child(Child && x) : Parent ( std::move(x) ) {}
};
Вот такой класс :
class Child : public Parent {
public:
using Parent::Parent;
} ;
будет использовать все конструкторы предка кроме копирования/перемещения + будут добавлены автоматически конструкторы копирования/перемещения.
Во втором примере :
class Child : public Parent {
public:
using Parent::Parent;
Child(const Child& other) {
cout << "Детский Копирования" << endl;
}
};
запись using Parent::Parent; создаёт собственные конструкторы для нового класса, используя вызов базового, кроме копирования/перемещения.
Объявление собственной функции копирования Child(const Child& other) отключает свойство компилятора и он не объявляет все эти функции сам, а программист должен сам все эти функции написать индивидуально. По-этому у вас не будет конструктора перемещения и операторов присваивания.