如何将类型A的数据写入B类格式

时间:2011-05-06 06:39:30

标签: c++ oop ooad

我正在实现一个生成结果的东西,并将它们写入某种格式的文件。

相当简单,但我希望这是动态的。

我会抛弃几节课。

数据 - 所有结果的基类
DataFile - 所有文件格式类型的基类,方法为addData(Data * data)

ErrorData - 从数据派生,包含有关错误的数据。
InfoData - 从数据派生,包含一般信息。

XmlFile - 派生自DataFile,包含XML格式的数据。
BinaryFile - 从DataFile派生,包含二进制格式的数据。

我的问题是:

我将实施如何将 ErrorData 写入 XmlFile

我不喜欢在答案中看到:

  1. 数据 的新成员函数, DataFile ErrorData XmlFile (因为这意味着我每次添加新 数据时都需要添加 strong>或 DataFile 派生类)
  2. 将类型转换为派生类型。
  3. 一般丑陋:)
  4. 我知道我的基本C ++虚拟化和事情,不需要过于具体。

    我很欣赏一些代码片段,但它们不那么模糊。

    我对制作 DataWriter 基类有一些想法,并从那些知道如何编写 数据 <的类中派生类/ strong>特定类型的某种类型的 DataFile ,但我对此具体细节有点不确定。

    编辑:

    我将以一个例子的形式澄清一点。

    我们有两种新的文件格式, FormatATxtFile FormatBTxtFile

    假设我们有一个 InfoData 对象,它有参数:

      

    讯息的行号:34
      消息内容:Hello World

    写入 FormatATxtFile 的对象在文件中如下所示:

      

    行:34; Txt:Hello World;类型:信息

    FormatBTxtFile 中,它看起来像这样:

      

    @ Info,34,Hello World

    一种将数据导出为其他格式的方法。我至少现在不需要导入。

    使用此代码的代码如下:

    DataFile * file = DataFileFactory::createFile(type);
    
    std::vector<Data*> data = generateData();
    
    file->setData(data);
    file->writeTo("./FileName"); // correct end is added by DataFile type, ie .txt
    

    编辑:

    似乎我没有弄清楚Xml和二进制文件格式出现什么问题。对不起。

    让我们使用与上面相同的 InfoData 对象并将其推送到XmlFile格式。它可能会在某个元素下产生类似的东西:

    <InfoLog>
        <Info Line="34">Hello World</Info>
    </InfoLog>
    

    我们假设 ErrorData 类具有以下参数:

      

    错误的行号:56
      错误文本:LINK:致命错误LNK1168
      错误消息之前的10行:text1 ...
      错误信息后的10行:text2 ...
      整个记录发生的事情:text3 ...

    现在,当它被推入XML格式时,它将需要完全不同的东西。

    <Problems>
        <Error>
            <TextBefore>text1...</TextBefore>
            <Text line = 56>
                LINK : fatal error LNK1168
            </Text>
            <TextAfter>text1...</TextAfter>
        </Error>
        ...
    </Problems>
    

    整个文件可能如下所示:

    <Operation>
        <InfoLog>
            <Info Line="34">Hello World</Info>
            <Info Line="96">Goodbye cruel World</Info>
        </InfoLog>
        <Problems>
            <Error>
                <TextBefore>text1...</TextBefore>
                <Text line = 56>
                    LINK : fatal error LNK1168
                </Text>
                <TextAfter>text1...</TextAfter>
            </Error>
            <Error>
                <TextBefore>sometext</TextBefore>
                <Text line = 59>
                    Out of cheese error
                </Text>
                <TextAfter>moretext</TextAfter>
            </Error>
        </Problems>
    </Operation>
    

4 个答案:

答案 0 :(得分:2)

不是试图找到一个把它放在一个类中的地方,而是一个新函数呢?

void copyData(const ErrorData *data, DataFile *output)
{
    // ...
}

然后,您可以为要转换的任何数据类型重载此函数。

或者,您也许可以使用模板:

template<typename A, typename B> copyData(const A *data, const B *output);

然后,您可以为需要支持的特定类型专门化模板。

答案 1 :(得分:2)

像标准库一样 - 与virtual函数/运算符一起使用。我们都可以使用istream&并使用operator>>从中提取我们想要的内容,而我们完全不关心基础流,无论是cinfstream还是stringstream。而是通过引用(data)来获取Data& data

答案 2 :(得分:1)

如果您考虑下面的代码,它提供了如何任意组合通用字段访问与通用字段流的最小说明 - 分解您的各种要求。如果适用性或实用性不明确,请告诉我....

#include <iostream>
#include <string>

struct X
{
    int i;
    double d;

    template <typename Visitor>
    void visit(Visitor& visitor)
    {
        visitor(i, "i");
        visitor(d, "d");
    }
};

struct XML
{
    XML(std::ostream& os) : os_(os) { }

    template <typename T>
    void operator()(const T& x, const char name[]) const
    {
        os_ << '<' << name << '>' << x << "</" << name << ">\n";
    }

    std::ostream& os_;
};

struct Delimiter
{
    Delimiter(std::ostream& os,
              const std::string& kvs = "=", const std::string& fs = "|")
      : os_(os), kvs_(kvs), fs_(fs)
    { }

    template <typename T>
    void operator()(const T& x, const char name[]) const
    {
        os_ << name << kvs_ << x << fs_;
    }

    std::ostream& os_;
    std::string kvs_, fs_;
};

int main()
{
    X x;
    x.i = 42;
    x.d = 3.14;

    XML xml(std::cout);
    Delimiter delimiter(std::cout);

    x.visit(xml);
    x.visit(delimiter);
}

答案 3 :(得分:1)

我一直在玩你的问题,这就是我的想法:

#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

class DataFile;

class Data {
public:
    virtual void serializeTo(DataFile*) = 0;
};

class DataFile {
public:
    void addData(Data* d) {
        _data.push_back(d);
    }
    virtual void accept(string paramName, string paramValue) {
        _map[paramName] = paramValue;
    }

    virtual void writeTo(string const& filename) = 0;

protected:
    list<Data*> _data;
    map<string, string> _map;
};

class FormatATxtFile: public DataFile {
public:
    void writeTo(string const& filename) {
        cout << "writing to " << filename << ".txt:" << endl;
        for(list<Data*>::iterator it = _data.begin(); it != _data.end(); ++it) {
            (*it)->serializeTo(this);       

            cout << "Line:" << _map["Line"] << "; "
                << "Txt:" << _map["Txt"] << "; "
                << "Type: " << _map["Type"]
                << endl;
        }
        cout << endl;
    }
};

class FormatBTxtFile: public DataFile {
public:
    void writeTo(string const& filename) {
        cout << "writing to " << filename << ".b-txt" << endl;
        for(list<Data*>::iterator it = _data.begin(); it != _data.end(); ++it) {
            (*it)->serializeTo(this);

            cout << "@" << _map["Type"] << "," << _map["Line"] << "," << _map["Txt"]
                << endl;
        }
        cout << endl;
    }
};

class InfoData: public Data {
    public:
        void serializeTo(DataFile* storage) {
            storage->accept("Line", line);
            storage->accept("Txt", txt);
            storage->accept("Type", "Info");
        }
        string line;
        string txt;
    };

int main()
{
    FormatATxtFile fileA;
    FormatBTxtFile fileB;
    InfoData info34;
    info34.line = "34";
    info34.txt = "Hello World";
    InfoData info39;
    info39.line = "39";
    info39.txt = "Goodbye cruel World";
    fileA.addData(&info34);
    fileA.addData(&info39);
    fileB.addData(&info34);
    fileB.addData(&info39);
    fileA.writeTo("./Filename");
    fileB.writeTo("./Filename");    
}
实际上,它并没有真正写入文件,但它很容易根据您的需要进行更改。

此示例代码的输出为:

  

写给./Filename.txt:行:34;
  Txt:Hello World;类型:信息热线:39;
  Txt:再见残酷的世界;类型:信息

     

写给./Filename.b-txt
  @ Info,34,Hello World
  @ Info,39,Goodbye cruel World

如您所见,Data需要为DataFile提供由名称和值标识的参数,DataFile的每个专精都会按照自己喜欢的方式处理它。

HTH