Производный класс наследует оператор присваивания базового класса? - PullRequest
2 голосов
/ 17 января 2012

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

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

#include <iostream>  
using namespace std;      
class Base  
{  
    public:  
    Base(int lx = 0):x(lx)  
    {  
    }  

    virtual Base& operator=( const Base &rhs)  
    {  
        cout << "calling Assignment operator in Base" << endl;  
        return *this;  
    }

    private:  
    int x;     
};      


class Derived : public Base  
{  
    public:  
    Derived(int lx, int ly): Base(lx),y(ly)  
    {  
    }

    Base& operator=(const Base &rhs)  
    {  
        cout << "Assignment operator in Derived"<< endl;  
        return *this;  
    }  

    private:  
    int y;    
};  



int main()  
{  
    Derived d1(10,20);  
    Derived d2(30,40);  
    d1 = d2;  
}  

Дает вывод

вызывающий оператор присваивания в базе

Я переписал оператор базового класса = в производный класс, поэтому, если производный класс наследует оператор базового класса =, его следует переопределить оператором = (который я написал в производном классе), а теперь оператор по умолчанию для производного класса = должен вызывать переопределенную версию, а не из оператора базового класса =.

Ответы [ 5 ]

4 голосов
/ 17 января 2012

Компилятор генерирует оператор присваивания по умолчанию для Derived (который скрывает оператор Base). Однако оператор присваивания по умолчанию вызывает все операторы присваивания членов класса и базовых классов.

3 голосов
/ 17 января 2012

Да, это так, просто оператор базового класса = скрыт оператором производного класса =.

1 голос
/ 15 октября 2014

Цитирование из стандарта (12.8.24):

Поскольку оператор назначения копирования / перемещения неявно объявляется для класс, если он не объявлен пользователем, базовый класс для копирования / перемещения оператор всегда скрыт соответствующим оператором присваивания производный класс (13.5.3). Объявление использования (7.3.3), которое вводит из базового класса оператор присваивания с типом параметра, который может быть оператором копирования / перемещения для производного класса не считается явным объявлением такого оператора и делает не подавлять неявное объявление оператора производного класса; оператор, введенный объявлением использования, скрыт неявно объявленный оператор в производном классе.

1 голос
/ 17 января 2012

Если я не понимаю, чего вы хотите достичь, вам нужен оператор присваивания для класса Derived, то есть тот, который принимает Derived в качестве ввода:

class Derived : public Base  
{  
/* ... */
public:
    Derived& operator=(const Derived &rhs)  
    {  
        cout << "Assignment operator in Derived"<< endl;  
        return *this;  
    }
};  

Что произошло в вашем коде (уже объяснено в ответе Бо Перссона и комментариях там): в Derived вы реализовали оператор присваивания, который принимает экземпляр Base; но в main() вы присваиваете экземпляр Derived; компилятор не видел оператора присваивания для Derived (тот, который принимает Base, не считается), и поэтому он сгенерировал оператор, который вызывает Base::operator=() и затем присваивания для элементов данных Derived. Если вы определили присвоение, как показано выше, этого не произойдет, и ваш оператор будет вызван; обратите внимание, что в этом случае присвоения Base и членов данных не будут выполняться автоматически.


Другая ситуация, если вы действительно хотите получить назначение от Base до Derived, например использовать его с другими производными Base. Тогда определенный вами оператор будет работать, но чтобы применить его к экземпляру Derived, вам нужно привести этот экземпляр к Base:

Derived d1(10,20);  
Derived d2(30,40);  
d1 = static_cast<Base&>(d2);

Само собой разумеется, что определенный вами оператор не может легко получить доступ к элементам данных rhs, специфичным для Derived: например, чтобы использовать rhs.y, вам нужно было бы «прекратить» rhs до Derived:

Derived& Derived::operator=(const Base& rhs)
{
    /* ... */
    Derived* rhs_d = dynamic_cast<Derived*>(&rhs);
    if( rhs_d )
        this->y = rhs_d->y;
}
0 голосов
/ 10 июня 2013

Если вы хотите добиться полиморфного поведения, это означает, что ваш базовый метод переопределен, вы должны написать следующее:

int main (){
    Derived * d1 = new Derived (10,20);  
    Derived * d2 = new Derived (30,40);
    Base * b1 = d1 ;
    Base * b2 = d2 ; 
    *b1 = *b2 ;
    *d1 = *d2 ;
} 

Это даст следующий вывод:

 $> Assignment operator in Derived.
 $> calling Assignment operator in Base. 
* 1006Итак, что я здесь делаю, так это неявное использование динамического приведения типов в c ++.Я не совсем уверен, работает ли это таким образом, но чтобы высказать свою точку зрения, я думаю, что это будет полезно.Когда я вызываю оператор присваивания с разыменованными b1 и b2, программа сначала ищет переопределенный метод функции, вызванной в производном классе, если он не находит, то вызывает базовый класс метода.Теперь, когда я вызываю оператор присваивания из d1, программа приводит производные к базе, и программа никак не может знать, что * d1 обозначает производный объект, поэтому она вызывает базовый метод.

Вот и все.

...