在ostream函数中使用递归函数作为输出

Using a recursive function as output in a ostream function

本文关键字:递归函数 输出 ostream 函数      更新时间:2023-10-16

我正在重载ostream运算符<lt;能够打印或写下我的ojbects。在其中一个例子中,我实际上是在file.txt中写入我的整个结构。structure对象实际上是一个二叉树,为了确保我从中得到每个元素,我需要一个递归函数。这是我尝试做的一个基本代码

out << parcour(tree); // recursive function

假设Parcour返回另一个结构,在该结构中,我有要写入输出文件的信息。我的递归函数内部是这样的:

node* parcour(node* node){
      if (node) {
         parcour(childnode(0));
         parcour(childnode(1));
         return node;
      }
   return nullptr;
}

所有包含我想要的信息的节点都由该函数返回。所以我认为问题是多个返回到一个std::cout实际上不起作用。我想知道是否有一个具有多个返回的函数(递归函数)可以作为输出,其中每个返回都将一次完成一个。

请不要注意语法错误,因为我的代码运行得很好,除了那个我无法解决的概念。

编辑:有些人一直要求我提供更多的代码,所以基本上我只会复制粘贴下面的原始代码(注意:所有内容都是法语:S):

我是Arbres.h

 #ifndef ARBRES_H
#define ARBRES_H
#pragma once
#include <iostream>
#include <vector>
using namespace std;
// noeud pour un arbre binaire contenant des informations de type T
template <class T>
class Noeud
{
private:
    T* element; // élément du noeud
    Noeud<T> *parent; // Pointeur vers le parent
    Noeud<T> *gauche; // Pointeur vers le fils gauche
    Noeud<T> *droit; // Pointeur vers le fils droit
public:
//constructeur du noeud
    Noeud()
    {
        element = nullptr;
        parent = nullptr;
        gauche = nullptr;
        droit = nullptr;
    }
// destructeur du noeud
    ~Noeud ()
    {
    }
// retourne l'enfant où "i" represente la position de l'enfant (droit ou gauche)
    Noeud<T> * Enfant(int i) const
    {
        if (i == 0)
            if (!gauche)
                return nullptr;
            else
                return gauche;
        else if (i == 1)
            if (!droit)
                return nullptr;
            else
                return droit;
        else
            return nullptr;
    }
// retourne le parent du noeud
    Noeud<T> *Parent () const
    {
        return parent;
    }
// retourne un pointeur vers l'élément du noeud (les infos)
    T *Element() const
    {
        return element;
    }
// modifie la valeur de l'élément
    void RemplacerElement( T *ele )
    {
        element = ele;
    }
//retourne vrai si le noeud est une feuille
    bool EstUneFeuille () const
    {
        return (!gauche) && (!droit);
    }
//retourne vrai si le noeud est une racine
    bool EstUneRacine () const
    {
        return (!parent);
    }
// détache l'enfant du noeud et retourne un pointeur vers ce noeud
    Noeud<T> *Detacher (Noeud<T>* Enfant)
    {
        Noeud<T> *temp;
        if (Enfant->parent->gauche == Enfant) {
            temp = Enfant->parent->gauche;
            Enfant->parent->gauche = nullptr;
        } else if (Enfant->parent->droit == Enfant) {
            temp = Enfant->parent->droit;
            Enfant->parent->droit = nullptr;
        } else
            return nullptr;
        return temp;
    }
// attache le noeud à l'enfant. Retourne vrai si l'opération est réussie
    bool Attacher(Noeud<T>* nouvelEnfant)
    {
        if (!gauche)
            gauche = nouvelEnfant;
        else if(!droit)
            droit = nouvelEnfant;
        else
            return 0;
        return 1;
    }
// attache les enfants au noeud. Retourne vrai si l'opération est réussie
    bool Attache(Noeud<T>* noeudCourant)
    {
        if (!gauche->parent)
            gauche->parent = noeudCourant;
        else if (!droit->parent)
            droit->parent = noeudCourant;
        else
            return 0;
        return 1;
    }
// Fonction Récursive qui crée un nouveau noeud et le place correctement dans l'arbre
    void CreerNouveauNoeud(istream& in, Noeud<T>* noeudCourant, int val) {
        if (val == 1) {
            if (!noeudCourant->Enfant(0)) {
                noeudCourant->Attacher(new Noeud<T>());
                noeudCourant->Attache(noeudCourant);
                noeudCourant = noeudCourant->Enfant(0);
                noeudCourant->RemplacerElement(new T());
                in >> *(noeudCourant->Element());
                return;
            }
            else if (!noeudCourant->Enfant(1)) {
                noeudCourant->Attacher(new Noeud<T>());
                noeudCourant->Attache(noeudCourant);
                noeudCourant = noeudCourant->Enfant(1);
                noeudCourant->RemplacerElement(new T());
                in >> *(noeudCourant->Element());
                return;
            }
            else {
                cout << "nERROR: Structure dans le fichier texte incorrect (limite de 2 sous-noeuds par noeud)" << endl;
                return;
            }
        }
        else {
            if (!noeudCourant->Enfant(1)) // S'il existe un noeud à droite s'est qu'on est rendu à ajouter la, sinon on va à gauche
                CreerNouveauNoeud(in, noeudCourant->Enfant(0), val - 1);
            else
                CreerNouveauNoeud(in, noeudCourant->Enfant(1), val - 1);
        }
        return;
    }
// le mot clé "friend" indique que la fonction peut utiliser les membres privés de la classe Noeud
    template<class U>
    friend istream& operator>> (istream& in, Noeud<U>& n);
    template<class U>
    friend ostream& operator<< (ostream& out, Noeud<U>& n);
};
// surcharge de l'opérateur >> pour un noeud
template <class T>
istream& operator>> (istream& in, Noeud<T>& n)
{
    in >> *n.element;
    return in;
}
// surcharge de l'opérateur << pour un noeud
template <class T>
ostream& operator<< (ostream& out, Noeud<T>& n)
{
    out << *n.element;
    return out;
}

// Patron de classe définissant la classe "Arbres"
// contenant des informations de type T
template <class T>
class Arbres
{
// Patron de classe définissant la classe "Arbres"
private:
    vector<Noeud<T>*> racines;
    Noeud<T>* noeudCourant;
public:
//constructeur d'une classe Arbres
    Arbres()
    {
        noeudCourant = nullptr;
    }
// destructeur d'une classe Arbres
    ~Arbres ()
    {
        supprimeArbre();
    }
    // ajoute un arbre de niveau 0 (un noeud) à la liste des racines
    int NouveauNoeud(Noeud<T>* n)
    {
        n->RemplacerElement(new T());
        racines.push_back(n);
        return racines.size() - 1;
    }
    // positionne le noeud courant sur le noeud racine d'indice i
    void SetCourant(int i)
    {
        if(i<racines.size())
            noeudCourant = racines[i];
    }
    // Déplace le noeud courant vers son enfant i
    void NaviguerVersEnfant(int i)
    {
        noeudCourant = noeudCourant->Enfant(i);
    }
    // Déplace le noeud courant vers son parent
    void NaviguerVersParent()
    {
        noeudCourant = noeudCourant->Parent();
    }
    // mets le noeud en position i de la liste racine comme enfant du noeud courant
    void joindreCourant(int i)
    {
        if (!noeudCourant->Enfant(0) || !noeudCourant->Enfant(1)) {
            noeudCourant->Attacher(racines[i]);
            racines[i] = nullptr;
            racines.erase(racines.begin()+i);
        }
        else {
            cout << "/nERROR: Aucun Enfant disponible sur le noeud Courant " << endl;
        }
    }
    // Détache le noeud courant de son parent
    void DetacherCourant()
    {
        if (noeudCourant->Parent()->Enfant(0) == noeudCourant) {
            noeudCourant->Detacher(noeudCourant->Enfant(0));
        }
        else
            noeudCourant->Detacher(noeudCourant->Parent()->Enfant(1));
    }
    // supprime le noeud courant
    void SupprimerCourant()
    {
        supprimeArbre(noeudCourant);
    }
    // retourne la liste des noeuds racines
    const vector<Noeud<T>*>* getRacine() const
    {
        return &racines;
    }
    // retourne le noeud courant
    const Noeud<T>* getCourant() const
    {
        return noeudCourant;
    }
    // fonction récursive qui parcours l'arbre et retourne chacun d'entre eux
    void parcourir(ostream& out, Noeud<T>* racine) {
        if (racine) {
            parcourir(out, racine->Enfant(0));
            parcourir(out, racine->Enfant(1));
            out << *racine;
        }
        return;
    }
    void supprimeArbre(Noeud<T>* racine) { // fonction récursive qui parcours l'arbre et supprime chaque noeud que l'on rencontre
        if (racine) {
            supprimeArbre(racine->Enfant(0));
            supprimeArbre(racine->Enfant(1));
            delete racine->Element();
            delete racine;
        }
        return;
    }
// le mot clé "friend" indique que la fonction peut utiliser les membres privés d'une classe Arbres
    template<class U>
    friend istream& operator>> (istream& in, Arbres<U>& n);
    template<class U>
    friend ostream& operator<< (ostream& out, Arbres<U>& n);
};
// surcharge de l'opérateur >> pour un objet de type Arbres<T>
template <class T>
istream& operator>> (istream& in, Arbres<T>& n)
{
    string buffer;
    while (in >> buffer) {
        int a = count(buffer.begin(), buffer.end(), '-'); // Compte le nombre de tiret pour déterminer le niveau du noeud dans l'arbres
        if (a == 0) {
            n.SetCourant(n.NouveauNoeud(new Noeud<T>()));
            n.noeudCourant->RemplacerElement(new T());
            in >> *(n.noeudCourant);
        }
        else {
            n.noeudCourant->CreerNouveauNoeud(in, n.noeudCourant, (a / 2));
        }
    }
    return in;
}
// surcharge de l'opérateur << pour un objet de type Arbres<T>
template <class T>
ostream& operator<< (ostream& out, Arbres<T>& n) 
{
    for (int x = 0; x < n.racines.size(); x++) {
        n.parcourir(out, n.racines[x]);
    }
    return out;
}
#endif

这是TP2.h

#ifndef TP2_H
#define TP2_H
#pragma once
# include <string>
# include <iostream>
using namespace std;
class Personne
{
    private:
        string nom;
        string prenom;
        int age;
        string metier;
    public:
        Personne();
        Personne(string leNom, string lePrenom, int lAge, string leMetier);
        ~Personne();
        friend istream& operator>> (istream& in, Personne& n);
        friend ostream& operator<< (ostream& out, Personne& n);
};
#endif

这是TP2.cpp

#include "TP2.h"
#include "Arbres.h"
#include <fstream>
#include <algorithm>
using namespace std;
Personne::Personne() {
    return;
}
Personne::Personne(string leNom, string lePrenom, int lAge, string leMetier)
{
    nom = leNom;
    prenom = lePrenom;
    age = lAge;
    metier = leMetier;
    return;
}
Personne::~Personne()
{
    return;
}
istream& operator>> (istream& in, Personne& n)
{
    in >> n.nom >> n.prenom >> n.age >> n.metier;
    return in;
}
ostream& operator<< (ostream& out, Personne& n)
{
    out << "tNom: " << n.nom << "ntPrenom: " << n.prenom << "ntAge: " << n.age << "ntMetier: " << n.metier << endl;
    return out;
}
int main(){
    ifstream Transaction;
    ifstream Data_input;
    ofstream Data_ouput;
    string transaction_fichier;
    string arbres_fichier;
    char op[1], FILENAME[50]; // Operateur, Nom d'un fichier
    int i; // Indice
    Arbres<Personne>* structure = nullptr;
    cout << "Entrer le nom du fichier transaction: ";
    cin >> transaction_fichier; // IMPORTANT : Le nom du fichier ne doit pas compoter d'espace!
    cout << endl;
    Transaction.open(transaction_fichier);
    if (Transaction.fail())
        cout << "nError 404 : File not foundn";
    while (!Transaction.eof()) {
        Transaction >> op;
        switch (op[0]) {
        case '*':
            Transaction >> *(*(structure->getRacine()))[structure->NouveauNoeud(new Noeud<Personne>())];
            break;
        case '&':
            Transaction >> i;
            structure->SetCourant(i);
            break;
        case '>':
            Transaction >> i;
            structure->NaviguerVersEnfant(i);
            break;
        case '<':
            Transaction >> i;
            structure->NaviguerVersParent();
            break;
        case '+':
            Transaction >> i;
            structure->joindreCourant(i);
            break;
        case '-':
            structure->DetacherCourant();
            break;
        case '!':
            structure->SupprimerCourant();
            break;
        case '%':
            cout << "Informations des personnes dans les noeuds racines:" << endl;
            for (unsigned int x = 0; x < (*(structure->getRacine())).size(); x++) {
                cout << *(*(structure->getRacine()))[x] << endl;
            }
            break;
        case '?':
            cout << "Informations de la personne dans le noeud courant:" << endl;
            cout << *(structure->getCourant()->Element()) << endl;
            break;
        case '#':
            if (structure) {
                for (unsigned int x = 0; x < (*(structure->getRacine())).size(); x++) {
                    structure->supprimeArbre((*(structure->getRacine()))[x]);
                }
            }
            else {
                Transaction >> FILENAME;
                Data_input.open(FILENAME);
                if (Data_input.fail())
                    cout << "nError 404 : File not foundn";
                structure = new Arbres<Personne>;
                Data_input >> *structure;
            }
            break;
        case '$':
            Transaction >> FILENAME;
            Data_ouput.open(FILENAME);
            Data_ouput << *structure;
            break;
        default:
            cout << "nError420 Operator not supported: " << op << endl;
            break;
        }
    }
    // Fin du programme
    return 0;
}

整个递归调用并没有按预期运行。输出的是从顶级parcour()调用返回的return值。由于内部递归调用似乎对返回值没有贡献,因此调用是发生还是跳过并不重要。

为了实现您所描述的目的,您需要将输出对象传递给parcour(),并在该函数中进行所需的任何输出。