2010-12-08 6 views
9

Ich spiele nur herum, um intelligente Zeiger zu verstehen und versuche, meins zu machen, aber ich stoße auf eine Situation, die ich nicht vollständig verstehe. Hier ist der Code:Warum ruft der Zuweisungsoperator den Konstruktor auf?

#include <iostream> 
template <class T> 
class Holder 
{ 
private: 
     T * obj; 
public: 
     Holder(T * tt) : obj(tt) 
     { 
       std::cout << "ctor : " << tt->dummy << std::endl; 
     } 
     T * operator ->() 
     { 
       return obj; 
     } 
     operator bool() 
     { 
       return obj; 
     } 
     T * const get() const 
     { 
       return obj; 
     } 
     void reset() {swap(0);} 
     void swap(T * other) 
     { 
       obj = other; 
     } 
     Holder & operator = (const Holder& holder) 
     { 
       obj = holder.get(); 
       return *this; 
     } 
     Holder(const Holder & holder) : obj(holder.get()) {} 
}; 

class A 
{ 
public: 
     int dummy; 
     A(int a) : dummy(a) {} 
}; 

int main() 
{ 
     A * a = new A(1); 
     Holder<A> holder(a); 
     A * b = new A(2); 
     holder = b; 

     std::cout << holder->dummy << std::endl; 

     return 0; 
} 

Der Code kompiliert und auf der Linie der holder = b; der Konstruktor von Holder Klasse aufgerufen wird. Ich dachte, Compiler würde einen Fehler geben. Es ist nicht der Assingment-Operator, aber warum ruft er Konstruktor auf?

+0

'Berechtigten zwei Konstruktoren hat, die man nennt? – suszterpatt

+0

@suszterpatt: Halter (T * tt) –

Antwort

13

holder = b versucht, von b zu Holder zuzuweisen. b ist vom Typ A*, und holder ist vom Typ Holder<A>.

Die Holder Vorlage definiert Zuordnung von einer anderen Instanz desselben Holder Typ, so dass der Compiler sucht nach einer Umwandlung von A* zu Holder<A>. Es findet den Konstruktor und verwendet diesen.

Konstruktoren, die genau ein Argument benötigen, können für implizite Konvertierungen verwendet werden, , es sei denn, wird mit dem Schlüsselwort explicit gekennzeichnet.

+0

+1 für "explizit". Vielen Dank. –

0

Sie haben einen Konstruktor, der ein T * nimmt. Ihre Zuweisung hat einen rhs-Zeiger, also konstruiert sie ein temp-obj mit diesem Zeiger als Argument und weist dies halter zu.

4

Sowohl der Konstruktor als auch der Zuweisungsoperator werden aufgerufen. Sie können dies überprüfen, indem Sie etwas in operator = drucken.

Dies geschieht, weil operator = definiert ist, um eine const Holder & zu nehmen, aber b ist vom Typ A *. Zuerst wird der Konstruktor Holder(T *) aufgerufen, um ein temporäres Objekt zu erstellen. Dann wird dieses Objekt holder bis operator = zugewiesen.

Wenn Sie eine operator =(const T *) definieren, wird nur der Zuweisungsoperator aufgerufen.

1

Ich sehe nicht, eine Version des Zuweisungsoperator, der eine rechte Seite von A * nimmt

A*  a  = new A(1); 
    Holder<A> holder(a); 
    A*  b   = new A(2); 

    // assigning object of type A* to Holder<A> 
    holder = b; 

    // No appropriate assignment operator provide. 
    // But a constructor is available to convert RHS parameter to correct type. 
    // So compiler generates the following code: 

    holder = Holder<A>(b); 

    // There is an appropriate assignment operator for this. 
    // So it compiles.