简体   繁体   English

禁止基类构造函数的输出

[英]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. 我有一系列告诉调试流(在本例中为std::cout )已创建的类,使我可以很好地跟踪程序执行。 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...). 我确实考虑过使用退格转义序列\\b ,并做足够的操作来删除前一条消息并不是很有效,但是它是调试信息,那时的性能不是那么关键……)。 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. 如果将输出重定向到文件等,则输出\\b将无济于事。

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. 此实现解决了Vlad的一些担忧。 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. 实际上,有一种方法,但是在这种情况下,仅由于基类直接使用std :: cout流这一事实而已。 One possible solution is to inherit std::streambuf class like this: 一种可能的解决方案是像这样继承std :: streambuf类:

#include <iostream>
#include <streambuf>

class DummyStreambuf : public std::streambuf {};

This step is needed because std::streambuf constructor are protected. 需要此步骤,因为std :: streambuf构造函数受到保护。 When you have DummyStreambuf (or whatever you name it), all you need to do is to change stream buffer on std::cout standard stream. 当您拥有DummyStreambuf(或其他名称)时,您所需要做的就是更改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;
}

Of course, there is room for improvement here. 当然,这里还有改进的空间。 You could write a simple singleton which could turn on and off std::cout output. 您可以编写一个简单的单例,该单例可以打开和关闭std :: cout输出。 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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