2012-01-17 2 views
2

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

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

#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; 
} 

Это дает выход

вызову Assignment оп Erator в базе

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

ответ

3

Да, это просто так, что оператор Base = скрыт от оператора Derived класса =.

+0

Мне интересно: Это объяснение кажется мне неправильным, утверждает, что мы ожидаем, что поведение Амита ожидается, и не объяснит наблюдаемое поведение. Если я, конечно, не ошибаюсь. Почему упреки? –

4

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

+0

Могу ли я переопределить оператор базового класса = в класс Derived? – Amit

+1

@Amit: вы не можете переопределить его. По определению не виртуальная функция не может быть переопределена, хотя она может быть скрыта. Возможно, вы хотите перегрузить оператор присваивания копий в 'Derived'. Если это так, то правильной сигнатурой является 'Derived & operator = (const Derived & rhs)'. Это подпись, которую ищет компилятор, когда вы выполняете 'd1 = d2'. Так как он не находит его, он вместо этого синтезирует оператор присваивания по умолчанию и вызывает 'Base :: operator = (const Base &)'. –

+0

@Steve: я изменил код, и теперь мой базовый класс opertor = является виртуальным. – Amit

0

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

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

Что случилось в коде (уже пояснялось в ответе Bo Persson и комментарии там): в 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

Если вы хотите достичь polymorfic поведения, это означает, что иметь свой базовый метод переопределен, вы должны быть написаны так:

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. 

Так что я здесь делаю это с помощью C++ динамического литья implici ждение. Я не совсем уверен, работает ли это так, но для того, чтобы понять, что это будет полезно. Когда i вызовет оператор присваивания с разыменованными b1 и b2, программа сначала ищет метод переопределения функции, вызванной производным классом, если он не найдет никого, тогда он вызывает класс базового метода. Теперь, когда я вызываю оператор присваивания из d1, программа отличает производную от базы, и никоим образом программа не может знать, что * d1 означает объект Derived, поэтому он вызывает базовый метод.

Это все люди.

1

Цитируя стандарта (12.8.24):

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

Смежные вопросы