开发者

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

开发者 https://www.devze.com 2023-03-25 02:59 出处:网络
I\'ve got a class outputInterface; that should handle the output (to files) of some data. The data is contained in objects of some custom classes, say dataClassA and dataClassB, that all derive from a

I've got a class outputInterface; that should handle the output (to files) of some data. The data is contained in objects of some custom classes, say dataClassA and dataClassB, that all derive from a common base class dataClassBase.

Now I want the data to be written to different files according to its type. So data of type dataClassA should go to fileA, data of type dataClassB should go to fileB and so on. As this output happens very often I would like the file handles (fileA and fileB) to stay open, i.e. I don't want to open and close the files for the output of each piece of data. One outputInterface object can be expected to exist all the time.

So what I would like to achieve is something like this:

  • Dynamically associate data of type dataClassA with the file handle fileA etc.
  • When receiving data of type dataClassA check whether fileA is already connected to a file, if not, open the file.

How can I get this behavior (or least something similar / better)? I've been thinking of making the file handles static members of dataClassA and dataClassB (or the base class dataClassBase?). But then, how do I take care of closing the files? I would have to somehow keep track of the dat开发者_如何学JAVAa types that have actually been used (the files that have actually been opened).


Try something like this:

#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

This is just a prove of concept and can be optimized in many ways. I would rather stick with overloaded functions than with runtime type checks.


This is fairly easy to implement in C++11, using an std::map<std::type_index, std::ostring*> outputMap. (In C++03, you'll have to implement the equivalent of std::type_index yourself.) You get the output stream using outputMap[typeid(*data)]. The only problem is getting the streams into the map to begin with: you can do something like:

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

But from where do you get the filename?

There's also the question of when you close the streams: you can't normally close an output stream in a destructor, since closing an output stream is an operation which can fail, and you need to detect and react to that failure. Probably with an exception, which is why you don't want to do it in a destructor.


Since the "data" part comes from dataClassBase, you can make a virtual/pure-virtual function 'WriteData` in this class, and let derive class implement it.

The class outputInterface may take objects of type dataClassBase and would directly call WriteData. Other than WriteData you may also add other virtual functions in dataClassBase

You did not mention relationship between outputInterface and dataClassBase

0

精彩评论

暂无评论...
验证码 换一张
取 消