2010-12-08 29 views
9

Je ne fais que jouer pour comprendre les pointeurs intelligents et essayer de faire le mien, mais je rencontre une situation que je ne comprends pas complètement. Voici le code:Pourquoi l'opérateur d'affectation appelle-t-il le constructeur?

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

Le code compile et sur la ligne de holder = b; le constructeur de Holder classe est appelée. Je pensais que le compilateur donnerait une erreur. Ce n'est pas l'opérateur d'assertion, mais pourquoi appelle-t-il le constructeur?

+0

'Holder' a deux constructeurs, que l'on est appelé? – suszterpatt

+0

@suszterpatt: Titulaire (T * tt) –

Répondre

13

holder = b tente d'affecter de b à Holder. b est de type A* et holder est de type Holder<A>.

Le modèle Holder définit l'affectation d'une autre instance du même type Holder, de sorte que le compilateur recherche une conversion de A*-Holder<A>. Il trouve le constructeur et l'utilise.

Constructors qui peut prendre un seul argument peut être utilisé pour les conversions implicites, à moins que vous les étiquette avec le mot-clé explicit.

+0

+1 pour "explicite". Merci. –

0

Vous avez un constructeur prenant un T *. Votre affectation a un pointeur rhs, donc elle construit un temp-obj avec ce pointeur comme argument et l'affecte à holder.

4

Le constructeur et l'opérateur d'affectation sont appelés. Vous pouvez vérifier cela en imprimant quelque chose au operator =.

Cela se produit car operator = est défini pour prendre un const Holder &, mais b est de type A *. Ainsi, le constructeur Holder(T *) est d'abord appelé pour créer un objet temporaire, puis cet objet est affecté à holder à operator =.

Si vous définissez un operator =(const T *), seul l'opérateur d'affectation sera appelé.

1

Je ne vois pas une version de l'opérateur d'affectation qui prend un côté droit de A *

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.