2015-06-24 12 views
5

Nie do końca rozumiem, dlaczego dla przypisania klasa pochodna nie wywołuje odpowiedniego operatora klasy bazowej, jeśli jej własna nie istnieje. Spójrz na kod:Operator przypisania C++ w klasie pochodnej

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

Ponieważ jest to kod nie kompiluje. Oczywiście jeśli zdefiniuję "operator =" dla B identycznego z tym dla A, wszystko działa, ale dlaczego operator "B =" nie jest wywoływany domyślnie, jeśli ten w klasie pochodnej nie jest zdefiniowany? Czy możesz pomóc rzucić nieco światła na tę kwestię?

Kompilator gcc mówi ../src/tito.cpp:40:4: error: no realable overloaded '=' pp = 0,0; ~~^~~~ ../src/tito.cpp:28:7: uwaga: funkcja kandydata (niejawny operator przypisania kopii) nie jest możliwa: brak znanej konwersji z "podwójnej" na "stałą B" dla pierwszego argumentu klasa B: publiczny A { ^ 1 wygenerowany błąd.

Czy możesz wyjaśnić, dlaczego to nie działa?

Odpowiedz

8

Jeśli nie zadeklarujesz operatora przypisania kopiowania, kompilator zadeklaruje go dla ciebie. Więc twoja klasa Bnaprawdę wygląda następująco:

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

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

Domniemana operator przypisania kopia skór na A::operator=(double) że napisałeś, więc to jedyny kandydat, który wyszukiwanie nazw znajdzie. Oczywiście nie jest to opłacalny kandydat, ponieważ double nie można zmienić na B, stąd błąd.

Aby użyć operatora A::operator=(double), trzeba wyraźnie dostosowania go do zakresu:

using A::operator=; 

Ale wtedy nie zamierzamy być przypisanie dowolnego z B części. Tak byłoby lepiej, aby być bardziej wyraźne:

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

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

    return *this; 
} 
+1

Tak, głównym uzasadnieniem jest 'operatora, który rodzica =' nie przypisuje udział dziecka tak niejawnie przy użyciu może easilly tworzyć niedziałających obiektów. – StenSoft

+0

Dziękuję za bardzo przydatny komentarz !! – Max

2

Kopia przypisanie operatora klasy pochodnej, która jest niejawnie zadeklarowanej przez kompilator ukrywa operatorów przypisania klasy bazowej. Użyj używając deklaracji w klasie pochodnej następujący sposób

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

Innym podejściem jest redeclare operator wirtualny przypisania w klasie pochodnej

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

W tym przypadku można wykorzystać polimorfizm. Na przykład

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

Wyjście programu jest

10 10 
20 20 
Powiązane problemy