首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++多态加载/保存

C++多态加载/保存
EN

Stack Overflow用户
提问于 2012-09-17 20:24:33
回答 6查看 712关注 0票数 4

我将一堆不同的对象保存并重新加载到一个文件中,这些对象都是从一个公共基础派生的,显然我需要存储类名(或类似的名称),以便在重新加载时创建正确的对象类型。

保存很容易:

代码语言:javascript
复制
class Base 
{
  virtual string className() const = 0;

  void saveToFile()
  {
    write(className());
    ... other writing stuff
  }
}

class Derived1: public Base 
{
  string className() const { return "Derived1"; };
  ...
}

class Derived2: public Base 
{
  string className() const { return "Derived2"; };
  ...
}

而且,如果你不介意复制字符串,加载也很容易……

代码语言:javascript
复制
static Base * Base::factory(const String &cname)
{
  if (cname == "Derived1")
    return new Derived1; 
  else if (cname == "Derived2")
    return = new Derived2; 
  else ...
}

void load()
{
  String cname = readString();

  Base * obj(Base::factory(cname);

  obj->readIt();
}

但是,重复的字符串冒犯了我对DRY的看法:理想情况下,className()可以是static virtual,但这是不允许的。我有一种感觉,我错过了一种明显的“干净”的方式,但我还看不到。有什么建议吗?

注意:好的,代码使用了一个工厂方法进行了轻微的调整。请注意,这实际上并没有解决问题!

注意#2:上面的代码并没有试图完美地表示最终的工厂模式。我不关心基类和派生类之间不必要的链接,也不关心扩展层次结构的潜在困难。我正在寻找能够简化代码而不是使其复杂化的答案。

EN

回答 6

Stack Overflow用户

发布于 2012-09-17 20:26:16

这就是你所能做的最好的事情了,你可以通过将if包装在工厂类中来清理它。

票数 3
EN

Stack Overflow用户

发布于 2012-09-17 21:27:45

这里有两件事。首先,为了避免必须写出两次名称,我在过去使用了类似以下内容:

代码语言:javascript
复制
class Derived : public Base
{
    //  ...
    static char const* className() { return "Derived"; }
    virtual char const* getClassName() const { return className(); }
                 //  overrides virtual function in the base class...
};

此外,如果您希望能够从外部源读取类,则需要某种类型的静态工厂函数,该函数向此类函数的映射注册自身。我会继续在Base中执行此操作

代码语言:javascript
复制
class Base
{
    // ...
protected:
    class Factory
    {
    protected:
        Factory( std::string const& type );
    public:
        virtual Base* constructFromFile( std::istream const& source ) const = 0;
    };
    typedef std::map <std::string, Factory const*> FactoryMap;
    static FactoryMap& factories();

    template <typename Derived>
    class ConcreteFactory : public Factory
    {
    public:
        ConcreteFactory() : Factory( Derived::className() ) {}
        virtual Base* constructFromFile( std::istream const& source ) const
        {
            return new Derived( source );
        }
    };

public:
    static Base* readFromFile( std::istream& source );
};


Base::FactoryMap&
Base::factories()
{
    static FactoryMap theOneAndOnly;
    return theOneAndOnly;
}

Base::Factory::Factory( std::string const& type )
{
    std::pair <FactoryMap::iterator, bool> results 
        = factories().insert( std::make_pair( type, this ) );
    assert (results.second);
}

Base* Base::readFromFile( std::istream& source )
{
    std::string type = readType( source );
    FactoryMap::const_iterator factory = factories().find( type );
    if ( factory == factories().end() ) {
        throw UnknownType(...);
    }
    return factory->second->constructFromFile( std::istream& source );
}

最后,对于每个派生类,您必须定义一个接受std::istream&的构造函数和一个Base::ConcreteFactory <Derived>的静态实例。(如上所述,这必须是静态成员。)

票数 3
EN

Stack Overflow用户

发布于 2012-09-17 20:26:51

显然,您需要工厂模式。点击此处了解更多信息http://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12459112

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档