2010-11-12 49 views
3

je class Personne (prénom, nom, adresse, âge) et les opérateurs surchargées < < et >> pour l'utiliser avec filestreams:Surcharger << and >> dans les classes héritées

ostream& operator<< (ostream& outStream, Person& person) 
{ 
    ... 
} 

istream& operator>> (istream& inStream, Person& person) 
{ 
    ... 
} 

Il fonctionne très bien - je peut lire et écrire facilement, mais j'ai ajouté deux classes héritées de Person: Student et Worker.

j'ai écrit pour les opérateurs surchargées, les très semblables à celles ci-dessus:

ostream& operator<< (ostream& outStream, Worker& worker) 
{ 
... 
} 

istream& operator>> (istream& inStream, Worker& worker) 
{ 
... 
} 


ostream& operator<< (ostream& outStream, Student& student) 
{ 
... 
} 

istream& operator>> (istream& inStream, Student& student) 
{ 
... 
} 

La seule différence sont deux champs dans chaque classe. Le problème est que lorsque j'utilise des opérateurs surchargés avec Student ou Worker, il semble que mon compilateur utilise des opérateurs pour personne. Probablement, il fait une conversion cachée de Student ou Worker à Person, mais par conséquent, ces champs supplémentaires ne sont pas écrits dans le fichier. en aval < < Les gens fonctionnent exactement comme en aval < < Étudiants ou offstrem Travailleurs. Peut-être que placer des déclarations d'opérateurs surchargées pour les classes héritées en premier, et pour Person plus tard dans le code résoudrait le problème, mais je ne trouve pas une solution élégante.

Si vous avez des idées sur la façon de gérer le problème ci-dessus, j'apprécierais.

+0

Cela est probablement un problème avec le code où vous appelez << and >>. Pouvez-vous poster du code autour de cette zone? – Chowlett

Répondre

11

Deux choses. Tout d'abord, faites vos opérateurs prennent des références à const, comme ceci:

ostream& operator<< (ostream& outStream, const Person& person) 

Pour résoudre votre problème, un modèle commun est de fournir vos types avec une méthode toString virtuelle protégée, et ont l'opérateur il suffit d'appeler cela. Vous pouvez ensuite surcharger cette méthode dans les sous-classes, et même réutiliser l'implémentation super-classe si vous souhaitez simplement ajouter des valeurs à la chaîne.

Exemple:

class Person { 
// other stuff 
protected: 
    virtual std::string toString(); 
    friend ostream& operator<< (ostream& outStream, const Person& person) 
}; 

ostream& operator<< (ostream& outStream, Person& person) 
{ 
    ostream << person.toString(); 
    return outStream; 
} 

Modifier En fait, j'aime larsmans suggestion encore mieux:

class Person { 
// other stuff 
protected: 
    virtual void print(ostream & stream) const; 
    friend ostream& operator<< (ostream& outStream, const Person& person) 
}; 

ostream& operator<< (ostream& outStream, Person& person) 
{ 
    person.print(outStream); 
    return outStream; 
} 

Ce sera plus facile à mettre en œuvre que l'idée toString, parce que vous n'avez pas besoin stringstream temporaire ou quelque chose comme ça pour construire la chaîne.

+1

L'opérateur d'extraction ne peut pas prendre de référence const. – wilhelmtell

+5

Ou membres protégés 'virtual void print (std :: ostream &) const' et' virtual void read (std :: istream &) '. –

+0

@larsmans: Merci, corrigé. –

0

J'appelle généralement une fonction virtuelle streamIn et streamOut dans les opérateurs de streaming surchargés, de cette façon je peux réellement créer une fonction de streaming de modèle qui fonctionne pour toutes les classes avec les fonctions streamIn et streamOut.

3

Très probablement le code qui appelle l'opérateur << accède à l'objet via un pointeur ou une référence à Personne, appelant ainsi l'opérateur pour le type personne. La manière habituelle de gérer ceci est de fournir une méthode virtuelle sur la classe parente (c'est-à-dire Personne) qui écrit (obtenant le flux comme argument), et appelle la méthode operator<< pour faire le travail. Vous devez fournir le operator<< uniquement pour la classe parente, le mécanisme de répartition virtuelle prendra soin de choisir la bonne méthode pour l'objet fourni.

class Person { 
    // ... 
protected: 
    virtual ostream& stream_write(ostream&) const; //override this in child classes 
    virtual istream& stream_read(istream&);  //this too 
public: 
    friend ostream& operator<< (ostream& stream, const Person& obj) 
     { return obj.stream_write(stream); } 
    friend istream& operator>> (istream& stream, Person& obj) 
     { return obj.stream_read(stream); } 
}; 
2

Vos opérateurs peuvent appeler une méthode virtuelle. Quelque chose comme ceci:

struct A 
{ 
    virtual ~A(){} 

    virtual std::ostream& Print(std::ostream &os) const 
    { 
    // print what you want 
    return os; 
    } 
}; 

struct B : A 
{ 
    virtual ~B(){} 

    virtual std::ostream& Print(std::ostream &os) const 
    { 
    // print what you want 
    return os; 
    } 
}; 

Ensuite, créez l'opérateur < < uniquement pour la classe de base:

std::ostream& operator<<(std::ostream &os, const A &a) 
{ 
    return a.Print(os); 
}