C++: возможно ли наследовать оператор присваивания?
Следующий код C++ не компилируется:
class BaseA {
protected:
BaseA &operator = (const BaseA &rhs);
};
template<typename T>
class BaseB {
public:
T &operator = (const T &rhs) {
return *static_cast<T *>(this);
};
};
class Derived :
public BaseA,
public BaseB<Derived> {
};
int main() {
Derived foo;
Derived bar;
foo = bar;
return 0;
};
Когда я пытаюсь скомпилировать это, я получаю жалобу, что BaseA &BaseA::operator = (const BaseA &)
не определено Есть несколько других вопросов, подобных этому, в stackru, но все они, похоже, касаются автоматической генерации компилятором Derived &Derived::operator = (const Derived &)
функция, которая вызывает BaseA::operator = (const BaseA&)
, В этом случае, хотя Derived
должен уже наследовать функцию с этой точной сигнатурой от BaseB<Derived>
, Если я последую совету по другому вопросу и добавлю using BaseB<Derived>::operator =;
в Derived
компилятор жалуется, что Derived &operator = (const Derived &)
не может быть перегружен.
Разве для класса просто невозможно унаследовать этот оператор?
Изменить: чтобы было ясно, я запутался, почему компилятор дает Derived
по умолчанию Derived &operator = (const Derived &)
когда он уже наследует T &operator (const T &) where [T = Derived]
от Base<Derived>
, Я могу понять, почему обычно по умолчанию создается оператор присваивания копии и переопределяет все унаследованные операторы присваивания, но в этом случае Derived
наследует оператор с точно такой же сигнатурой, что и оператор присваивания копии. Есть ли способ написать BaseB
так что его подклассы используют этот оператор?
3 ответа
Нет, оператор присваивания operator=
не наследуется. У вас нет по умолчанию
Derived& operator=(const BaseA& a);
в вашем производном классе.
Однако создается оператор присваивания по умолчанию:
Derived& operator=(const Derived& a);
и это вызывает оператор присваивания из BaseA
, Так что дело не в наследовании оператора присваивания, а в его вызове через сгенерированный по умолчанию оператор в вашем производном классе. И некоторые примечания: Стандарт говорит (12.8):
Оператор присваивания должен быть реализован нестатической функцией-членом с ровно одним параметром. Поскольку оператор оператора копирования = неявно объявляется для класса, если он не объявлен пользователем (12.8), оператор назначения базового класса всегда скрыт оператором копирования копии производного класса.
а затем оператор присваивания производного вызова вашей базы
Неявно определенный оператор назначения копирования / перемещения для класса X, не являющегося объединением, выполняет присваивание для каждого элемента копирование / перемещение его подобъектов. Прямые базовые классы X назначаются первыми в порядке их объявления в списке базовых спецификаторов, а затем назначаются непосредственные нестатические члены-данные X в том порядке, в котором они были объявлены в определении класса.,
Оператор присваивания является одной из специальных функций-членов. Если вы не предоставите его самостоятельно, компилятор сгенерирует его для вас, назначив базы, а затем членов. Если у какой-либо базы нет оператора присваивания, он будет сгенерирован.
Ваша проблема в том, что вы объявили оператор присваивания для BaseA
, но не предоставили определения. Поскольку он объявлен, компилятор не сгенерирует его для вас, но попытается вызвать его для копирования BaseA
субобъект. Затем компоновщик не сможет найти определение.
Обратите внимание, что для конкретного случая назначения наследование базовой реализации не имеет смысла. Если бы это использовалось, как только одна база имела оператор присваивания, остальная часть объекта не была бы назначена. Семантика операции будет нарушена в большинстве случаев.
Вы можете наследовать операторы базового класса и все другие методы, если вы не объявите его в базовом классе - оператор присваивания по умолчанию будет сгенерирован компилятором, если вы объявите его - когда вам нужно будет предоставить собственную реализацию, то есть вы получите ошибку из-за operator= не определен в вашем классе BaseA, только объявлен.