簡體   English   中英

C ++如何根據應寫入的數據類型動態選擇文件句柄?

[英]C++ How to dynamically select a file handle according to the type of data that should be written?

我有一個class outputInterface; 應該處理一些數據的輸出(到文件)。 數據包含在某些自定義類的對象中,例如dataClassAdataClassB ,它們都從通用基類dataClassBase派生。

現在,我希望根據數據類型將數據寫入不同的文件。 因此, dataClassA類型的數據應轉到fileAdataClassB類型的數據應轉到fileB ,依此類推。 由於此輸出經常發生,因此我希望文件句柄( fileAfileB )保持打開狀態,即,我不想打開和關閉用於輸出每個數據的文件。 可以一直認為存在一個outputInterface對象。

所以我想要實現的是這樣的:

  • dataClassA類型的數據與文件句柄fileA等動態關聯。
  • 接收到dataClassA類型的數據時,請檢查fileA是否已連接到文件,如果沒有,請打開該文件。

如何獲得這種行為(或至少類似/更好的行為)? 我一直在考慮使文件處理dataClassAdataClassB (或基類dataClassBase嗎?)的靜態成員。 但是,我該如何關閉文件呢? 我將不得不以某種方式跟蹤實際已使用的數據類型(實際已打開的文件)。

嘗試這樣的事情:

#ifndef OUTPUTINTERFACE?H   
#define OUTPUTINTERFACE?H

#include <string>
#include <fstream>
#include <map>

class DataClass
{
public:
    virtual bool WriteData(std::ofstream& FStream) = 0;
};
class DataClass1 :
    public DataClass
{    
    virtual bool WriteData(std::ofstream& FStream)
    {
        FStream << "teletubbies";
    }
};    
class DataClass2 :
    public DataClass
{
    virtual bool WriteData(std::ofstream& FStream)
    {
        FStream << "garbage";
    }
};


class OutputInterface
{
public:
    OutputInterface()
    {
    }
    ~OutputInterface()
    {
        //Release stream pointers
    }
    template<typename T>
    bool WriteData(T& Data)
    {
        std::string dClassUID = std::string(typeid(T).name);
        tFStreamMap::iterator it this->streamMap.find(dClassUID);
        std::ofstream* stream = NULL;

        if(it != streamMap.end())
        {
            stream = it->second;
        }
        else
        {
            stream = new std::ofstream();
            stream->open(dClassUID + ".txt");
            streamMap.insert(std::make_pair(dClassUID, stream));
        }

        Data.WriteData(stream);
    }
private:
    typedef std::map<std::string, std::ofstream*> tFStreamMap;
    tFStreamMap streamMap;
};    

#endif

這只是概念的證明,可以通過多種方式進行優化。 我寧願堅持使用重載函數而不是運行時類型檢查。

這在C ++ 11中使用std::map<std::type_index, std::ostring*> outputMap相當容易實現。 (在C ++ 03中,您必須自己實現std::type_index的等效項。)您可以使用outputMap[typeid(*data)]獲得輸出流。 唯一的問題是開始將流放入地圖中:您可以執行以下操作:

std::ostream*& destPtr = outputMap[typeid(*data)];
if ( destPtr == NULL ) {
    destPtr = new std::ofstream("...");
}
std::ostream& dest = *destPtr;

但是,從哪里獲得文件名?

還有一個問題,當您關閉流時:您通常無法在析構函數中關閉輸出流,因為關閉輸出流是一個可能會失敗的操作,您需要檢測到該失敗並對之做出反應。 可能有一個例外,這就是為什么您不想在析構函數中這樣做。

由於“數據”部分來自dataClassBase ,因此您可以在此類中創建一個虛擬/純虛擬函數“ WriteData”,然后讓派生類實現它。

outputInterface可以采用dataClassBase類型的對象,並直接調用WriteData 除了WriteData您還可以在dataClassBase添加其他虛擬函數

您沒有提到outputInterfacedataClassBase之間的關系

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM