Наследование оператора присваивания
Есть этот код:
#include <iostream>
class Base {
public:
Base(){
std::cout << "Constructor base" << std::endl;
}
~Base(){
std::cout << "Destructor base" << std::endl;
}
Base& operator=(const Base& a){
std::cout << "Assignment base" << std::endl;
}
};
class Derived : public Base{
public:
};
int main ( int argc, char **argv ) {
Derived p;
Derived p2;
p2 = p;
return 0;
}
Результат после компиляции с помощью g++ 4.6:
Constructor base
Constructor base
Assignment base
Destructor base
Destructor base
Почему оператор присваивания базового класса вызывается, хотя говорят, что оператор присваивания не наследуется?
Ответы
Ответ 1
У вас нет значения по умолчанию
Derived& operator=(const Base& a);
в вашем классе Derived
.
Создается оператор присваивания по умолчанию:
Derived& operator=(const Derived& a);
и это вызывает оператор присваивания из Base
. Таким образом, это не вопрос наследования оператора присваивания, а вызов его через созданный по умолчанию оператор в производном классе.
Ответ 2
Собственно, то, что называется, неявно определено operator =
для Derived
. Определение, предоставленное компилятором, в свою очередь вызывает operator =
для Base
, и вы видите соответствующий вывод. То же самое с конструктором и деструктором. Когда вы оставляете его компилятору для определения operator =
, он определяет его следующим образом:
Derived& operator = (const Derived& rhs)
{
Base1::operator =(rhs);
...
Basen::operator =(rhs);
member1 = rhs.member1;
...
membern = rhs.membern;
}
где Base1,...,Basen
являются основами класса (в порядке их указания в списке наследования), а member1, ..., membern
являются членами Derived (не считая членов, которые были унаследованы) в том порядке, в котором вы их объявили в определение класса.
Ответ 3
Вы также можете использовать "using":
class Derived : public Base{
public:
using Base::operator=;
};
http://en.cppreference.com/w/cpp/language/using_declaration
Я прочитал этот пост несколько раз, прежде чем кто-то помог мне с этим.
Ответ 4
Стандарт говорит (12.8):
Оператор присваивания должен выполняться нестационарным членом функция с одним параметром. Поскольку назначение копии оператор operator = неявно объявлен для класса, если не объявлен пользователем (12.8), оператор присваивания базового класса всегда скрыт оператором присваивания копии производного класса.
а затем оператор присваивания производного вызова вашей базы
Неявно определенный оператор присваивания копирования/перемещения для неединичного класс X выполняет поэтапное копирование/перемещение назначения своих подобъектов. Прямые базовые классы X назначаются первыми, в порядке их объявление в списке-спецификаторе базы, а затем немедленное нестатические элементы данных X назначаются в том порядке, в котором они были объявлены в определении класса.
Ответ 5
Это связано с тем, что созданный по умолчанию оператор присваивания вызывает его оператор базового присвоения, т.е. он не наследуется, а все еще называется частью оператора присваивания по умолчанию.
Ответ 6
Оператор присваивания действительно не унаследован. Наследование этого оператора позволит вам назначить Base
для Derived
, однако Base b; p = a;
(по праву) не скомпилируется.
Что происходит, так это то, что компилятор генерирует operator=
, так как вы не определили пользовательский для Derived
. Автогенерированный operator=
вызовет операторы присваивания всех базовых классов и всех членов. В этом аспекте он почти такой же, как конструкторы/деструкторы, которые также называют соответствующую функцию для всех базовых элементов/членов.