2017-08-04 8 views
0

J'ai un problème de base pour comprendre ce qu'est ostream exactement. Je sais que c'est une classe de base pour le flux de sortie, mais je ne sais pas trop quand l'utiliser et pourquoi l'utiliser au lieu de simplement dire std :: cout. J'ai donc ici cet exemple où je dois créer une nouvelle classe nommée stack avec une fonction pop() (comme dans la classe déjà fournie par C++).en utilisant ostream comme argument de fonction

Ici, list_node est une structure constituée de deux éléments: la clé (qui est un entier) et un inter-point qui pointe vers l'entier suivant.

Définition de list_node (déjà donné):

struct list_node { 
int key; 
list_node∗ next; 
// constructor 
list_node (int k, list_node∗ n) 
: key (k), next (n) {} 
}; 

et est ici la définition de la classe (déjà en question):

class stack { 
public: 
void push (int value) {...} 
... 
private: 
list_node∗ top_node; 
}; 

et voici la partie avec laquelle je suis ayant des problèmes avec:

void print (std::ostream& o) const 
{ 
const list_node* p = top_node; 
while (p != 0) { 
o << p->key << " "; // 1 5 6 
p = p->next; 
} 
} 

Je ne comprends pas pourquoi ils utilisent ostream & o comme argument de fonction. N'ont-ils pas simplement pris le top_node comme argument et utilisé aussi la fonction .next dessus (.next lit le prochain list_node) et ensuite ils auraient pu l'imprimer avec la fonction std :: cout. Pourquoi est-il préférable de le faire comme ils l'ont fait?

+3

Tout d'abord, 'std :: ostream' n'est certainement pas ** un autre nom pour' std :: cout'. Former est une classe de base, la seconde est un objet de type non spécifié. Deuxièmement, on ne sait pas ce que vous demandez. – SergeyA

+0

Cette méthode est-elle définie à l'intérieur de la pile? Est-ce que 'top_node' est un membre de la classe de pile? Ce n'est vraiment pas clair ce que vous demandez; On dirait qu'il y a beaucoup de contexte manquant. –

+0

Vous devriez fournir un [mcve] –

Répondre

0

Pourquoi est-il préférable de le faire comme ils l'ont fait?

Je ne suis pas sûr de votre question, et je ne suis pas sûr que ce soit un meilleur moyen. Peut-être que l'intention était pour la flexibilité. Voici l'exemple de ma bibliothèque d'applications:


Quand je déclare un attribut de données comme un ostream

class T431_t 
{ 
    // ... 
    std::ostream*  m_so; 
    // ... 

je peux trivialement utiliser cet attribut pour fournir un rapport « où-m_so points » . Dans cette application, il existe plusieurs exemples de * mso < < ... en cours d'utilisation. Voici l'exemple principal.

inline void reportProgress() 
{ 
    // ... 
    *m_so << " m_blk = " << m_blk 
     << " m_N = 0x" << std::setfill('0') << std::hex << std::setw(16) << m_N 
     << " " << std::dec << std::setfill(' ') << std::setw(3) << durationSec 
     << "." << std::dec << std::setfill('0') << std::setw(3) << durationMSec 
     << " sec (" << std::dec << std::setfill(' ') << std::setw(14) 
     << digiComma(m_N) << ")" << std::endl; 
    // ... 
} 

Notez que dans le constructeur de classe (cteur), il y a une affectation par défaut pour m_so à std :: Cout.

T431_t(uint64_t maxDuration = MaxSingleCoreMS) : 
     // .. 
     m_so (&std::cout), // ctor init - default 
     // .. 
{ 
    // ... 

Lorsque l'utilisateur sélectionne l'option de traitement à double fil, qui est une option de ligne de commande pour exécuter l'application dans environ 1/2 du temps en utilisant les deux processeurs de mon bureau, les rapports peuvent devenir difficile à lire si j'autorise l'entrelacement des deux flux de sortie indépendants (sur l'écran de l'utilisateur). Ainsi, dans l'instance d'objet exécutée par le thread 2, m_so est défini quelque chose de différent. L'attribut de données suivant capture et conserve la sortie du thread 2 pour diffusion ultérieure vers std :: cout.

std::stringstream m_ssMagic; // dual threads use separate out streams 

Discussion 2 est lancé et le fil fixe, il est m_so privé:

void exec2b() // thread 2 entry 
{ 
    m_now = Clock_t::now(); 

    m_so = &m_ssMagic; // m_so points to m_ssMagic 

    // ... 

    m_ssMagic << " execDuration = " << m_ssDuration.str() 
       << " (b) " << std::endl; 
} // exec2b (void) 

Alors que le thread 1 utilise std :: Cout, et le fil 2 utilise m_ssMagic, 'main' (fil 0) attend simplement les jointures.

Les jointures coordonnent la fin du fil, généralement à peu près au même moment. Main (thread 0) puis cout le contenu de m_ssMagic.

//... 
// main thread context: 
case 2: // one parameter: 2 threads each runs 1/2 of tests 
{ // use two new instances 
    T431_t t431a(MaxDualCoreMS); // lower test sequence 
    T431_t t431b(MaxDualCoreMS); // upper test sequence 

    // 2 additional threads started here 
    std::thread tA (&T431_t::exec2a, &t431a); 
    std::thread tB (&T431_t::exec2b, &t431b); 

    // 2 join's - thread main (0) waits for each to complete 
    tA.join(); 
    tB.join(); 

    // tA outputs directly to std::cout 
    // tB captured output to T431_t::m_ssMagic. 

    // both thread 1 and 2 have completed, so ok to: 
    std::cout << t431b.ssMagicShow() << std::endl; 

    retVal = 0; 
} break; 

Pour être complet, voici

std::string ssMagicShow() { return (m_ssMagic.str()); } 

Résumé

j'ai écrit l'application de fil unique en premier. Après avoir obtenu ce travail, j'ai cherché un moyen «simple» d'utiliser le deuxième noyau sur mon bureau.

Dans le cadre de mon premier refactor, j'ai) ajouté "std :: ostream m_so" initialisé à & std :: cout, et b) trouvé toutes les utilisations de std :: cout. La plupart d'entre eux j'ai simplement remplacé par "* m_so". J'ai ensuite c) confirmé que je n'avais pas cassé la solution à un seul fil. Assez facile, et a travaillé le premier essai.

L'effort suivant a implémenté l'option 'dual-thread' de la ligne de commande.

Je pense que cette approche s'appliquera à mon bureau suivant, lorsque le budget le permet.


Et d'un point de vue de la POO, cet effort fonctionne parce que std :: ostream est dans la hiérarchie des classes des deux std :: et std :: Cout stringstream. Ainsi

"std::cout is-a std::ostream", 

et

"std::stringstream is-a std::ostream". 

Ainsi m_so peut indiquer par exemple de l'une classe dérivée, et fournir méthode virtuelle « ostream accès » à une ou l'autre destination.