IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

surcharge d'opérateur avec parametre


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut surcharge d'opérateur avec parametre
    Bonjour,

    J'aimerai surcharger l'opérateur << mais ajouter un parametre à ma surcharge.
    Exemple épuré:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class mon_printf
    {
        mon_printf& operator<<(char const*)
        {
            printf(" %s ", str);
            return *this;        
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class ma_classe : public mon_printf
    {
        ma_classe& trace()
        {
            printf("trace depuis la classe ma_classe : ");
            return *this;
        }
        void test()
        {
            trace() << "test\n";
        }
    }
    Dans cet exemple, si j'apelle ma_classe.test() j'aurai affiché :
    trace depuis la classe ma_classe : test

    Maintenant j'aimerai ajouter un parametre a la fonction trace() mais qui soit transmit aux fonctions de la classe mon_printf.
    Le but serait d'avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class ma_classe : public mon_printf
    {
        ma_classe& trace(int niveau)
        {
            if(niveau >= niveau_log_courrant)
                    printf("trace depuis la classe ma_classe : ");
            return *this;
        }
        void test()
        {
            trace(1) << "test\n";
        }
    }
    donc je voudrais qu'en fonction du parametre niveau, avoir l'affichage du printf dans ma_classe mais aussi dans mon_printf (l'affichage de "test" dans cet exemple).

    Comment faire ?

    merci.

    PS : le but de cette classe mon_printf est d'avoir un log thread safe (ce qui n'est pas le cas de std::cout), et d'avoir des logs qui m'affichent dans quelle classe je me trouve. Par extention le log pourra ajouter tout seul des affichages pour savoir par exemple l'adresse de la classe ou certaines valeurs de cette classe.
    Il suffira d'ecrire ca dans la fonction trace() de chaque classe.

  2. #2
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Rajouter une couche d'abstraction résoud pas mal de problèmes, le tien en particulier.

    De plus, il y a un problème dans ta conception: toutes tes classes sont des "tarcer" ? Dis moi si je me trompe, mais ma_classe n'a pas pour but primaire d'effectuer des logs, si ? Si la réponse est non, alors hériter de mon_printf est une erreur de conception.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    #include <iostream>
     
    // interface adapteur pour un tracer (printf, autre...)
    class TracerAdapter
    {
    public:
    	virtual TracerAdapter& operator<<( const char* ) = 0;
    	virtual ~TracerAdapter(){}
    };
     
    class PrintTracer : public TracerAdapter
    {
    public:
    	PrintTracer& operator<<( const char * str )
    	{
    		printf("%s", str);
    		return *this;
    	}
    };
     
    class Logger
    {
    	Logger()
    	{
    		tracer = NULL;
    	}
     
    	TracerAdapter* tracer;
    	static Logger* instance;	
    	int logLevel;
    	int currentLevel;
    public:
     
    	static Logger& log()
    	{
    		return log(0);
    	}
     
    	static Logger& log( int level )
    	{
    		instance->currentLevel = level;
    		if( level >= instance->logLevel )
    			*instance->tracer << "trace: ";
    		return *instance;
    	}
     
    	static Logger& get()
    	{
    		return *instance;
    	}
     
    	void setLevel( int level )
    	{
    		logLevel = level;
    	}	
     
    	void setTracer( TracerAdapter* adapter )
    	{
    		tracer = adapter;
    	}
     
    	Logger& operator<<( const char * str )
    	{
    		if( currentLevel >= logLevel )
    			*tracer << str;
    		return *this;
    	}
     
    	virtual ~Logger()
    	{
    		delete tracer;
    	}
    };
     
    Logger* Logger::instance = new Logger();
     
    class MyClass
    {
    public:
    	MyClass()
    	{
    		Logger::log() << "from MyClass: " << "hello\n";
    		Logger::log(3) << "from MyClass: " << "BANG BANG BANG\n";
    	}
    };
     
    int main() {
    	Logger::get().setTracer( new PrintTracer() );
    	Logger::get().setLevel( 2 );
    	MyClass a;
    	return 0;
    }
    Si tu peux avoir plusieurs loggers dans ton application, alors vire le côté singleton de la classe.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    merci pour cet exemple.
    Par contre j'ai pas bien compris l'interet d'avoir 3 classes (TracerAdapter, PrintTracer, et Logger). PrintTracer et Logger ne suffiraient pas ?
    Et puis il faut definir chaque surcharge en double (dans printtracer et dans logger). Car il faut surcharger char *, int, etc... il peut y en avoir beaucoup.

    Ensuite pourquoi dis tu que si ca ne fait pas parti du but primare de MaClasse d'afficher elle ne doit pas en hériter ?

    Enfin, le probleme de ta solution c'est qu'elle n'est pas thread safe.
    Vu que j'ai plusieurs instances de MaClasse qui sont apellés depuis des thread différents, je vais me retrouver avec des logLevel incohérents.

  4. #4
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    merci pour cet exemple.
    Par contre j'ai pas bien compris l'interet d'avoir 3 classes (TracerAdapter, PrintTracer, et Logger).
    Ensuite pourquoi dis tu que si ca ne fait pas parti du but primare de MaClasse d'afficher elle ne doit pas en hériter ?
    Parce que tout simplement, l'héritage est un couplage fort qui dit qu'une sous-classe est une - sorte de la - sur-classe. C'est à dire que maclasse est en réalité un mon_printf, ce qui n'est généralement pas le cas. Il vaut mieux séparer tes classes métier de tes classes d'implémentation.

    L'intérêt de TracerAdapter c'est de pouvoir avoir plusieurs types de Tracer (printf, log dans un fichier, ou que sais-je) sans intervenir dans la classe logger.

    Enfin, le probleme de ta solution c'est qu'elle n'est pas thread safe.
    Vu que j'ai plusieurs instances de MaClasse qui sont apellés depuis des thread différents, je vais me retrouver avec des logLevel incohérents.
    Vu que je ne sais pas quel solution multithread tu utilises, je ne peux pas protéger le code. C'est à toi de le faire.

    De plus, je n'ai pas dit que mon code était 100% cohérent et que c'était la bonne manière de faire. Je voulais juste te montrer qu'en rajoutant une couche entre ton Tracer et ta classe métier, tu peux résoudre le problème. Si tu veux un Logger thread-safe et qui soit robuste, va voir du côté des librairies déjà existante (et il n'en manque pas).

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Le probleme pour rendre ta solution thread safe, c'est que je vois pas comment faire.
    lorsqu'on fait :
    Logger::log(3) << "from MyClass: " << "BANG BANG BANG\n";

    il faudrait locker un mutex lors de l'appel de log(3). Ca c'est facile.
    Mais comment delocker le mutex a la fin du log courrant.
    Car si il faut le faire manuellement a chaque log ca devient trop lourd.

  6. #6
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Une solution simple serait de soit encore rajouter une couche pour la sécurité multi-thread, soit utiliser des macros.

    mais je te conseille plutôt d'aller voir vers les solutions de logging déjà existants, ça sera très certainement plus robuste que le bout de code que j'ai pondu là comme exemple.

    Ou bien une manière simple de faire que en sorte que ça fonctionne en multi-thread sans utilisation de l'opérateur <<:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #include <iostream>
     
    class Logger
    {
    	int logLevel;
     
    public:
    	Logger( int lLevel ) :
    		logLevel( lLevel )
    	{
    	}
     
    	virtual ~Logger()
    	{
    	}
     
    	template<typename... Values>
    	void log( int level, std::string s, Values... values ) const
    	{
    		if( level >= logLevel )
    			printf( s.c_str(), values... );
    	}
    };
     
    class MaClasse
    {
    	const Logger& logger;
     
    	template< typename... Values >
    	void log( int level, std::string s, Values... values ) const
    	{
    		std::string prepend = "from MaClasse: ";
    		logger.log( level, prepend + s, values... );
    	}
    public:
    	MaClasse( const Logger& l ) :
    		logger( l )
    	{
    	}
     
    	void run()
    	{
    		log( 0, "%s", "Hello from MaClasse" );
    		log( 2, "%s", "PAN PAN PAN" );
    	}
     
    };
     
    int main()
    {
    	Logger l(2);
    	MaClasse m(l);
    	m.run();
    }
    (utilisation de C++11)

    Utiliser l'opérateur << pour tout et pour rien ça ne convient pas imo, dans ce cas-ci ça allourdit énormément le code sans raison particulière, je trouve.

    Je te conseille quand même de te tourner vers une libraire de logging.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    ok merci. J'essaye la librairie log4cpp qui a l'air pas trop mal.

  8. #8
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Test boost::log (accepté mais pas encore dans boost). Sa envoie bien .
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. surcharge d'opérateur avec classes différentes
    Par weird73 dans le forum C++
    Réponses: 7
    Dernier message: 23/01/2013, 18h03
  2. Surcharge opérateur[] avec plusieurs paramètres
    Par darkman19320 dans le forum C++
    Réponses: 2
    Dernier message: 29/03/2012, 15h26
  3. Problème avec la surcharge d'opérateur de flux
    Par spirzouf dans le forum Débuter
    Réponses: 10
    Dernier message: 06/09/2011, 21h16
  4. Problème de surcharge d'opérateur flux avec pointeur
    Par eleve_prog dans le forum Débuter
    Réponses: 4
    Dernier message: 18/04/2011, 18h41
  5. Réponses: 9
    Dernier message: 09/05/2008, 23h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo