繁体   English   中英

禁止基类构造函数的输出

[英]Suppress output from base class constructor

我有一系列告诉调试流(在本例中为std::cout )已创建的类,使我可以很好地跟踪程序执行。 我有几个类是不是抽象的基类的子类,在创建子类实例时会导致出现双重消息。 当从子类中调用输出时,我想抑制基类构造函数中的输出。 我知道,如果没有一点花哨的技巧,这可能是不可能的。

我确实考虑过使用退格转义序列\\b ,并做足够的操作来删除前一条消息并不是很有效,但是它是调试信息,那时的性能不是那么关键……)。 我不确定这种方法的可移植性或有效性。

欢迎任何想法,感谢您的努力!

没有办法抑制基本构造函数中的代码,除非基本构造函数中的代码本身检查某些条件。 您可以通过例如向基础构造函数传递一个特殊标志(具有不禁止调试输出的默认值)来实现。

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将无济于事。

一个不错的解决方案是创建一个返回字符串的虚函数,并输出该函数的结果。 但是,这不适用于您的情况(从构造函数调用),因为在基本构造函数运行期间,虚拟函数的行为就像实例是基本类型而不是派生的。

此实现解决了Vlad的一些担忧。 主要区别在于构造函数签名,该签名不受日志逻辑的影响,尽管类现在是模板,这可能令人恐惧,但是众所周知,那里没有免费的午餐。 :)因此,我们开始:

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

实际上,有一种方法,但是在这种情况下,仅由于基类直接使用std :: cout流这一事实而已。 一种可能的解决方案是像这样继承std :: streambuf类:

#include <iostream>
#include <streambuf>

class DummyStreambuf : public std::streambuf {};

需要此步骤,因为std :: streambuf构造函数受到保护。 当您拥有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;
}

当然,这里还有改进的空间。 您可以编写一个简单的单例,该单例可以打开和关闭std :: cout输出。 这是单线程环境的一种可能的实现:

#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