C ++ Как динамически выбирать дескриптор файла в соответствии с типом данных, которые должны быть записаны? - PullRequest
0 голосов
/ 03 августа 2011

У меня есть class outputInterface;, который должен обрабатывать вывод (в файлы) некоторых данных. Данные содержатся в объектах некоторых пользовательских классов, например, dataClassA и dataClassB, которые все происходят из общего базового класса dataClassBase.

Теперь я хочу, чтобы данные записывались в разные файлы в соответствии с их типом. Таким образом, данные типа dataClassA должны идти в fileA, данные типа dataClassB должны идти в fileB и так далее. Поскольку этот вывод происходит очень часто, я бы хотел, чтобы описатели файлов (fileA и fileB) оставались открытыми, т.е. я не хочу открывать и закрывать файлы для вывода каждого фрагмента данных. Можно ожидать, что один outputInterface объект будет существовать все время.

Итак, чего бы я хотел достичь, так это:

  • Динамически связать данные типа dataClassA с дескриптором файла fileA и т. Д.
  • При получении данных типа dataClassA проверьте, подключен ли fileA к файлу, если нет, откройте файл.

Как я могу получить это поведение (или хотя бы что-то похожее / лучшее)? Я думал о том, чтобы заставить файл обрабатывать статические члены dataClassA и dataClassB (или базовый класс dataClassBase?). Но тогда, как мне позаботиться о закрытии файлов? Мне бы пришлось как-то отслеживать типы данных, которые фактически использовались (файлы, которые фактически были открыты).

Ответы [ 3 ]

2 голосов
/ 03 августа 2011

Попробуйте что-то вроде этого:

#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

Это всего лишь подтверждение концепции и ее можно оптимизировать многими способами.Я бы предпочел придерживаться перегруженных функций, чем проверок типов во время выполнения.

1 голос
/ 03 августа 2011

Это довольно легко реализовать в 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;

Но откуда вы берете имя файла?

Существует также вопрос о том, когда вы закрываете потоки: вы не можете обычно закрывают выходной поток в деструкторе, так как закрывают выход Поток - это операция, которая может дать сбой, и вам нужно обнаружить и отреагировать к этой неудаче. Вероятно, с исключением, поэтому вы не хочу сделать это в деструкторе.

0 голосов
/ 03 августа 2011

Поскольку часть «data» происходит от dataClassBase, вы можете создать виртуальную / чисто виртуальную функцию «WriteData» в этом классе и позволить классу наследования реализовать ее.может принимать объекты типа dataClassBase и напрямую вызывать WriteData.Кроме WriteData вы также можете добавить другие виртуальные функции в dataClassBase

Вы не упомянули связь между outputInterface и dataClassBase

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...