2010-12-01 20 views
0

J'ai une série de classes qui indique au flux de débogage (std::cout dans ce cas) qu'il a été créé, ce qui me permet de bien suivre l'exécution du programme. J'ai plusieurs classes qui sont des sous-classes de classes de base qui ne sont pas abstraites, ce qui entraîne un double message lorsqu'une instance de sous-classe est créée. Je voudrais supprimer la sortie dans le constructeur de la classe de base quand il est appelé à partir d'une sous-classe. Je sais que ce n'est probablement pas possible sans un tour de fantaisie, si c'est même possible du tout. J'ai pensé à utiliser la séquence d'échappement backspace \b, et en faire juste assez pour supprimer le message précédent pas vraiment efficace, mais c'est l'information de débogage, la performance n'est pas si critique que ça ...). Je ne suis pas certain de la portabilité ou de l'efficacité de cette approche.Supprimer la sortie du constructeur de la classe de base

Toutes les idées sont les bienvenues, merci pour l'effort!

Répondre

2

Il n'existe aucun moyen de supprimer le code dans le constructeur de base, sauf si le code dans le constructeur de base vérifie lui-même certaines conditions. Vous pouvez y parvenir par exemple passer un drapeau spécial au constructeur de base (ayant la valeur par défaut n'interdisant pas la sortie de débogage).

class Base 
{ 
    public: 
    Base(bool suppressDebugInfo = false) 
    { 
     if (!suppressDebugInfo) 
      cout << "hallo from base" << endl; 
    } 
}; 

class Derived : public Base 
{ 
    public: 
    Derived(bool suppressDebugInfo = false) : Base(true) 
    { 
     if (!suppressDebugInfo) 
      cout << "hallo from derived" << endl; 
    } 
}; 

\b s de Sortie » ne sera pas aider si votre sortie est redirigé vers un fichier, etc.

Une solution décente pourrait être de créer une fonction virtuelle qui renvoie une chaîne, et sortie le résultat de cette fonction. Cela ne fonctionnera cependant pas pour votre cas (appel du constructeur), car pendant l'exécution du constructeur de base, les fonctions virtuelles se comportent comme si l'instance était du type de base, non dérivée.

+0

Merci, cela ressemble à la meilleure solution, je ne me soucie pas vraiment de la signature du constructeur adapté ... il semble être une solution assez simple. – rubenvb

0

En fait, il y a un moyen, mais dans ce cas, seulement grâce au fait que les classes de base utilisent directement le flux std :: cout. Une solution possible est d'hériter classe std :: streambuf comme ceci:

#include <iostream> 
#include <streambuf> 

class DummyStreambuf : public std::streambuf {}; 

Cette étape est nécessaire parce que le constructeur std :: streambuf sont protégés. Quand vous avez DummyStreambuf (ou quel que soit votre nom), tout ce que vous devez faire est de changer le tampon de flux sur le flux standard std :: cout.

int main() 
{ 
DummyStreambuf dummy; 

std::cout << "test" << std::endl; 

// save default stream buffer for later use 
std::streambuf *buff = std::cout.rdbuf(&dummy); 

// this line shouldn't print 
std::cout << "test" << std::endl; 

// restore default stream buffer 
std::cout.rdbuf(buff); 

std::cout << "test" << std::endl; 
} 

Bien sûr, il y a place à amélioration ici. Vous pourriez écrire un singleton simple qui pourrait activer et désactiver la sortie std :: cout. Voici une implémentation possible pour un environnement monothread:

#include <iostream> 
#include <streambuf> 

class DummyStreambuf : public std::streambuf {}; 

class CoutSwitch 
{ 
private: 
    DummyStreambuf _dummyBuf; 
    std::streambuf *_coutBuf; 

    CoutSwitch() : _coutBuf(std::cout.rdbuf()) {} 

    static CoutSwitch &instance() { 
    static CoutSwitch _instance; 
    return _instance; 
    } 

public: 
    static void turnOn() { 
    std::cout.rdbuf(instance()._coutBuf); 
    } 

    static void turnOff() { 
    std::cout.rdbuf(&instance()._dummyBuf); 
    } 
}; 

int main() 
{ 
std::cout << "test" << std::endl; 

CoutSwitch::turnOff(); 

std::cout << "test" << std::endl; 

CoutSwitch::turnOn(); 

std::cout << "test" << std::endl; 
} 
+0

Comment cela permettrait-il aux classes CT dérivées d'écrire des résultats et d'empêcher les CT de classe de base de le faire? – foraidt

+0

std :: cout a un lien externe et il est unique à une instance de programme. Si vous modifiez le flux std :: cout, vous le modifiez pour n'importe quel code client. Pour citer: rubenvb: "J'ai une série de classes qui indique au flux de débogage (std :: cout dans ce cas) qu'il a été créé, ce qui me permet de bien suivre l'exécution du programme. – LavaScornedOven

+0

(1) si la classe de base initialise certains membres en tant que partie de son constructeur, leur sortie sera également supprimée, (2) votre solution nécessite d'appeler 'CoutSwitch :: turnOff()' avant instanciation _any_ de toute classe dérivée; (3) Je ne vois pas comment cette solution peut être étendue au cas où il y a une classe de plus dérivée de la classe dérivée – Vlad

1

Cette implémentation répond à certaines des préoccupations de Vlad. La principale différence réside dans la signature du constructeur, qui n'est pas affectée par la logique de journalisation, bien que les classes soient maintenant des modèles, ce qui pourrait être effrayant, mais comme vous le savez tous, il n'y a pas de repas gratuit. :) Donc, nous y voilà:

#include <iostream> 

template< bool IsLeafClass = true > 
class AbstractBase 
{ 
    public: 
     AbstractBase() { 
      if (IsLeafClass) 
       std::cout << "AbstractBase" << std::endl; 
     } 
}; 

template< bool IsLeafClass = true > 
class Base : AbstractBase<false> { 
    public: 
     Base() { 
      if (IsLeafClass) 
       std::cout << "Base" << std::endl; 
     } 
}; 

typedef Base<> CBase; 

template< bool IsLeafClass = true > 
class Derived : public Base<false> { 
    private: 
     CBase _base; 

    public: 
     Derived() { 
      if (IsLeafClass) 
       std::cout << "Derived" << std::endl; 
     } 
}; 

typedef Derived<> CDerived; 

template < bool IsLeafClass = true > 
class DerivedMore : public Derived<false> { 
    private: 
     CDerived _derived; 
     CBase _base; 

    public: 
     DerivedMore() { 
      if (IsLeafClass) 
       std::cout << "DerivedMore" << std::endl; 
     } 
}; 

typedef DerivedMore<> CDerivedMore; 

int main() 
{ 
    std::cout << "logging for b" << std::endl; 
    CBase b; 

    std::cout << std::endl << "logging for d" << std::endl; 
    CDerived d; 

    std::cout << std::endl << "logging for dm" << std::endl; 
    CDerivedMore dm; 
}