2015-11-03 1 views
0

Je suis en train de surcharger l'opérateur < < pour un modèle de classe, mais le compilateur me donne une erreur de lien. Le but est de pouvoir envoyer un pointeur de classe de base dé-référencé à std :: cout afin que l'opérateur dérivé < < soit appelé.Modèles et opérateur de surcharge <<

Est-ce possible?

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 
private: 
    T data_; 
}; 

template <typename T> 
Derived<T>::Derived(T data) 
    : IBase(), 
     data_(data) 
{ 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
{ 
    os << dt.data_; 
    return os; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 


    // Question 1 
    Derived<int> der(234); 
    std::cout << der; 

    // Question 2 
    //IBase* base = new Derived<int>(5); 
    // std::cout << *base 
} 

Voici les erreurs:

erreur LNK2001: symbole externe non résolu « classe std :: basic_ostream> & __cdecl opérateur < < (classe std :: basic_ostream

&, classe Derived const &) "(?? 6 @ YAAAV? $ Basic_ostream @ DU? $ Char_traits @ D @ std @@@ st ? D @@ AAV01 @ $ ABV dérivé @ H @@@ Z)

et

LNK1120 erreur fatale: 1 unresolved externals

Répondre

2

Vous devez declarate opérateur ami comme modèle trop

template<typename T1> 
friend std::ostream& operator<<(std::ostream& os, const Derived<T1>& dt); 
+0

Merci! Ça a fait l'affaire –

0

remplacer
friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

avec

template<typename D> 
friend std::ostream& operator<<(std::ostream& os, const Derived<D>& dt); 
0

Votre problème immédiat est que l'opérateur doit être basé sur un modèle. Cependant, votre objectif ultime ne peut pas être atteint par le biais de modèles uniquement car le déréférencement IBase* vous obtient une instanciation IBase& - modèle qui se produit à la compilation et le compilateur n'a pas accès au type d'exécution.

Votre opérateur basé sur un modèle ne sera donc jamais utilisé si vous transmettez un IBase* déréférencé à operator <<.

Au lieu de cela, ajouter une fonction de sortie virtuelle à la base et la remplacer:

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
    virtual std::ostream& output(std::ostream&) const = 0; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    virtual std::ostream& output(std::ostream& os) const 
    { 
     os << data; 
     return os; 
    } 
private: 
    T data_; 
}; 

std::ostream& operator<<(std::ostream& os, const IBase& dt) 
{ 
    return dt.output(os); 
} 
+0

Merci pour ça! J'ai posé cette question séparément il y a quelques minutes, postez votre réponse pour que je puisse l'accepter. http://stackoverflow.com/questions/33496137/virtual-operator-and-templates –

0

Vous n'avez pas besoin de faire votre friend un modèle:

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

Cela doit être changé :

friend std::ostream& operator<< <>(std::ostream& os, const Derived<T>& dt); 

La fonction operator<< aura besoin d'être visible avant la déclaration friend pour que ce formulaire fonctionne.

Vous devriez préférer ce formulaire à friend un modèle parce que vous n'avez pas besoin de toutes les instanciations de l'opérateur pour être friend s, juste un d'entre eux.

2

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);

déclare une version non modèle friend, de sorte que vous auriez à mettre en œuvre

std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

pour chaque T que vous utilisez:

std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) { 
    return os << dt.data_; 
} 

Et ainsi de suite. Une façon de le faire sans le code en double est avec définition dans la classe:

template <typename T> 
class Derived : public IBase 
{ 
public: 
    explicit Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
    { 
     return os << dt.data_; 
    } 
private: 
    T data_; 
}; 

Demo

Une autre alternative est de rendre le modèle de fonction.

// Forward declarations 
template <typename T> class Derived; 
template <typename T> std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

Et puis à Derived, vous avez 2 choix:

  • DÉCLARE chaque ami de la méthode du modèle:

    template <typename T2> 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T2>& dt); 
    

    donc std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) a accès aux membres privés de Derived<int>, mais aussi à ceux de Derived<char>

    Demo

  • Declare que le modèle qui correspond à l'argument:

    friend std::ostream& operator<< <>(std::ostream& os, const Derived& dt); 
    

    et ainsi std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) n'a pas accès aux membres privés de Derived<char>.

    Demo