简体   繁体   中英

Suppress output from base class constructor

I have a series of classes that tells the debug stream ( std::cout in this case) that it has been created, allowing me to follow the program execution nicely. I have several classes that are subclasses of base classes which are not abstract, which results in a double message when a subclass instance is created. I would like to suppress the output in the base class constructor when it is called from a subclass. I know this probably isn't possible without some fancy trick, if it is even possible at all.

I did think of using the backspace escape sequence \\b , and doing just enough of that to delete the previous message not really efficient, but it's debug info, performance isn't that critical then...). I'm not sure of the portability or effectiveness of this approach.

Any ideas are welcome, thanks for the effort!

There's no way to suppress the code in the base constructor, unless the code in the base constructor checks some condition itself. You may achieve this by eg passing a special flag to the base constructor (having default value NOT prohibiting the debug output).

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;
    }
};

Outputting \\b 's won't help if your output is redirected to a file etc.

A decent solution could be to create a virtual function which returns a string, and output the result of that function. This won't however work for your case (calling from constructor), as during the base constructor run the virtual functions behave as if the instance is of the base type, not derived.

This implementation addresses some of Vlad's concerns. The main difference lies in the constructor signature, which is not affected by logging logic, although classes are templates now, which could be frightening, but as you all know, there's no free lunch out there. :) So, here we go:

#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;
}

Actually, there is a way, but in this case, only thanks to the fact that the base classes are using the std::cout stream directly. One possible solution is to inherit std::streambuf class like this:

#include <iostream>
#include <streambuf>

class DummyStreambuf : public std::streambuf {};

This step is needed because std::streambuf constructor are protected. When you have DummyStreambuf (or whatever you name it), all you need to do is to change stream buffer on std::cout standard stream.

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;
}

Of course, there is room for improvement here. You could write a simple singleton which could turn on and off std::cout output. Here is one possible implementation for single-threaded environment:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM