簡體   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