2015-06-24 4 views
5

Я не совсем понимаю, почему для присваивания производный класс не вызывает соответствующий оператор базового класса, если его собственный не существует. Посмотрите на код:Оператор присваивания C++ в производном классе

#include <iostream> 
using namespace std; 

class A{ 
protected: 
    void myWrite(){ 
    cout << " Base " <<endl; 
    } 
public: 
    double x,y; 
    A(): x{0},y{0}{}; 
    virtual A & operator=(double g){x=g;y=g;return *this;} 
    virtual ~A(){}; 
    virtual void doneit(){myWrite();} 
}; 


class B: public A{ 
protected: 
public: 
    B():A(){}; 
    virtual ~B(){}; 
    virtual void doneit(){myWrite();} 
}; 

int main() { 
    A jj; 
    B pp; 

    pp=0.0; 
    return 0; 
} 

Как это код не компилируется. Конечно, если я определяю «operator =» для B, идентичный тому, что для A, все работает, но почему B «operator =» не вызывается по умолчанию, если тот, что в производном классе не определен? Не могли бы вы помочь пролить свет на эту проблему?

Компилятор gcc говорит ../src/tito.cpp:40:4: ошибка: нет жизнеспособного перегруженного '=' pp = 0.0; ~~^~~~ ../src/tito.cpp:28:7: note: функция-кандидат (неявный оператор присваивания копии) не жизнеспособна: неизвестное преобразование из 'double' в 'const B' для 1-го аргумента класс B: общественный A { ^ 1 погрешность сгенерирована.

Не могли бы вы объяснить, почему это не работает?

ответ

8

Если вы не объявляете оператор присваивания копии, компилятор объявит его для вас. Так что ваш класс Bдействительно выглядит следующим образом:

class B : public A { 
public: 
    // explicit 
    B(); 
    virtual ~B(); 
    virtual void doneit(); 

    // implicit 
    B(const B&); 
    B& operator=(const B&); 
}; 

неявного оператор копирующего присваивания шкуры в A::operator=(double), что вы написали, так что это единственный кандидат, который имя поиск будет найти. Конечно, это не жизнеспособный кандидат, так как double не конвертируется в B, следовательно, ошибка.

Чтобы использовать оператор A::operator=(double), вы должны явно привести его в рамки:

using A::operator=; 

Но тогда вы не собираетесь назначить любого из B части. Так было бы лучше, чтобы быть более явным:

B& operator=(double g) { 
    // B stuff here 

    // A stuff 
    A::operator=(g); 

    return *this; 
} 
+1

Да, основное обоснование является 'оператор этого родителя =' не присваивает часть ребенка так неявно с помощью нее можно easilly создавать сломанные объекты. – StenSoft

+0

Спасибо за очень полезный комментарий! – Max

2

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

class B: public A{ 
protected: 
public: 
    using A::operator =;  
    B():A(){}; 
    virtual ~B(){}; 
    virtual void doneit(){myWrite();} 
}; 

Другого подхода заключается в переобъявить оператор виртуального присваивания в производном классе

B & operator=(double g) { A::operator =(g) ;return *this;} 

В этом случае вы можете использовать полиморфизм. Например

#include <iostream> 

class A 
{ 
public: 
    double x,y; 
    A(): x{0}, y{0} {} 
    virtual A & operator =(double g){ x = g; y = g; return *this; } 
    virtual ~A(){} 
}; 


class B: public A 
{ 
public: 
    B() : A(){} 
    virtual B & operator =(double g) override { A::operator =(2 * g) ; return *this; } 
    virtual ~B(){} 
}; 

int main() 
{ 
    A a; 
    B b; 

    A *p = &a; 

    *p = 10; 

    std::cout << p->x << ' ' << p->y << std::endl; 

    p = &b; 

    *p = 10; 

    std::cout << p->x << ' ' << p->y << std::endl; 

    return 0; 
} 

Выход программы

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