Наследование оператора присваивания - PullRequest
18 голосов
/ 06 февраля 2012

Есть этот код:

#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

Почему оператор присваивания базового класса называется, хотя говорят, что оператор присваивания не наследуется?

Ответы [ 6 ]

34 голосов
/ 06 февраля 2012

На самом деле, то, что называется, является неявно определенным 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 (не считая членов, которые были унаследованы) в порядке, который вы объявили в определение класса.

25 голосов
/ 27 мая 2015

Вы также можете использовать «использование»:

class Derived : public Base{
public:
    using Base::operator=;
};

http://en.cppreference.com/w/cpp/language/using_declaration

Я прочитал этот пост несколько раз, прежде чем кто-то помог мне с этим.

17 голосов
/ 06 февраля 2012

В вашем классе Derived нет значения по умолчанию

Derived& operator=(const Base& a);

.

Однако создается оператор назначения по умолчанию:

Derived& operator=(const Derived& a);

и это вызывает оператор присваивания из Base.Так что дело не в наследовании оператора присваивания, а в его вызове через сгенерированный по умолчанию оператор в вашем производном классе.

8 голосов
/ 06 февраля 2012

Стандарт говорит (12.8):

Оператор присваивания должен быть реализован с помощью нестатической функции-члена с ровно одним параметром.Поскольку оператор оператора копирования = неявно объявляется для класса, если он не объявлен пользователем (12.8), оператор назначения базового класса всегда скрыт оператором копирования копии производного класса.

и затем оператор присваивания производного вызова вашего базового

Неявно определенный оператор присваивания для копирования / перемещения для класса X без объединения выполняет присваивание для каждого элемента копирование / перемещение его подобъектов.Прямые базовые классы X назначаются первыми в порядке их объявления в списке базовых спецификаторов, а затем назначаются непосредственные нестатические члены-данные X в том порядке, в котором они были объявлены в определении класса..

0 голосов
/ 06 февраля 2012

Оператор присваивания действительно не наследуется.Наследование этого оператора позволит вам присвоить Base для Derived, однако Base b; p = a; (по праву) не сможет скомпилироваться.

В результате компилятор генерирует operator=, поскольку выне определил пользовательский для Derived.Автоматически сгенерированный operator= вызовет операторы присваивания всех всех базовых классов и всех членов.В этом аспекте это почти то же самое, что конструкторы / деструкторы, которые также вызывают соответствующую функцию на всех основаниях / элементах.

0 голосов
/ 06 февраля 2012

Это потому, что созданный оператор присваивания по умолчанию вызывает его базовый оператор присваивания, то есть он не наследуется, но все еще вызывается как часть оператора присваивания по умолчанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...