我有一种情况,我有一个界面,定义了某一类的行为,以填补一定的作用在我的程序,但在这个时候我不是100%肯定的如何许多类,我会写,以填补这一作用。然而,在同一时间,我知道,我想让用户能够选择,从GUI组合/列表框,其具体类实现接口,他们要用来填补一定的作用。我想GUI能一一列举所有可用的课程,但是我宁愿不要回去和改变旧的代码时,我决定实施一个新的类填补的作用(可以是个月,从现在)

有些事情我认为:

  1. 使用一枚举
    • 赞成:
      1. 我知道怎么做
      1. 我将需要更新更新的枚举,当我增加一个新类
      2. 丑陋的迭代过
  2. 使用某种类型的 static 列表目的,在该接口,并增加一个新元素的定义范围内的文件的执行类
    • 赞成:
      1. 不会有改变旧的代码
    • 缺点:
      1. 甚至不知道如果这是可能的
      2. 不知道什么样的信息存储这样一个工厂的方法可以选择适当的构造(也许是个地图之间的串的和功能的指针,返回一个指向一个目的接口)

我猜这是一个问题(或类似于一个问题),更有经验的程序员可能遇到之前(常常),还有可能是共同解决这种问题,这是几乎可以肯定比什么都好我能上来。因此,我该怎么做?

(P.S.我搜索,但是所有我发现了这个,它不是相同的: 我怎么列举的所有项目,实施一个通用的接口?.它出现他已经知道如何来解决这个问题我试图出来。)

编辑:我重新命名为题为"我怎么可以跟踪。"而不是"我怎么可以枚举的...",因为原来的问题听起来像是我更感兴趣,审查的运行环境,在那里为什么我是真的感兴趣的是编纂时的书。

有帮助吗?

解决方案

创建单独在这里你可以登记您的类别与一个指向一个造物主的功能。在加拿大养恤金计划的文件的具体类注册的每一类。
事情是这样的:

class Interface;
typedef boost::function<Interface* ()> Creator;

class InterfaceRegistration
{
    typedef map<string, Creator> CreatorMap;
public:
    InterfaceRegistration& instance() {  
        static InterfaceRegistration interfaceRegistration;
        return interfaceRegistration;
    }

    bool registerInterface( const string& name, Creator creator )
    {
        return (m_interfaces[name] = creator);
    }

    list<string> names() const
    {
        list<string> nameList;  
        transform(
            m_interfaces.begin(), m_interfaces.end(), 
            back_inserter(nameList) 
            select1st<CreatorMap>::value_type>() );
    }

    Interface* create(cosnt string& name ) const 
    { 
        const CreatorMap::const_iterator it 
            = m_interfaces.find(name);  
        if( it!=m_interfaces.end() && (*it) )
        {
            return (*it)();
        }
        // throw exception ...
        return 0;
    }

private:
    CreatorMap m_interfaces;
};


// in your concrete classes cpp files
namespace {
bool registerClassX = InterfaceRegistration::instance("ClassX", boost::lambda::new_ptr<ClassX>() );
}

ClassX::ClassX() : Interface()
{
    //....
}

// in your concrete class Y cpp files
namespace {
bool registerClassY = InterfaceRegistration::instance("ClassY", boost::lambda::new_ptr<ClassY>() );
}

ClassY::ClassY() : Interface()
{
    //....
}

其他提示

我依稀记得做一些类似的多年前。你的选择(2)几乎是我做了什么。在这种情况下,它是一个 std::mapstd::stringstd::typeinfo.在每一个.cpp文件我是注册的类是这样的:

static dummy = registerClass (typeid (MyNewClass));

registerClass 需要一个 type_info 目和简单地返回 true.你有初始化的变量确保, registerClass 被称为期间启动时间。简单地呼唤 registerClass 在全球名称空间是一个错误。并且使得 dummy 静让你重复使用的名称的汇编单位没有一名碰撞。

我提到这篇文章中实施自我注册类工厂的一个类似的描述TimW的答案,但是它有很好的招使用一个模板化工厂的代理类,以处理的物体的登记。很值得一看:)

自登记的对象,在C++-> http://www.ddj.com/184410633

编辑

这里的测试应用程序我没有(收拾一点;):

object_factory.h

#include <string>
#include <vector>
// Forward declare the base object class
class Object;
// Interface that the factory uses to communicate with the object proxies
class IObjectProxy {
public:
    virtual Object* CreateObject() = 0;
    virtual std::string GetObjectInfo() = 0;
};
// Object factory, retrieves object info from the global proxy objects
class ObjectFactory {
public:
    static ObjectFactory& Instance() {
        static ObjectFactory instance;
        return instance;
    }
    // proxies add themselves to the factory here 
    void AddObject(IObjectProxy* object) {
        objects_.push_back(object);
    }
    size_t NumberOfObjects() {
        return objects_.size();
    }
    Object* CreateObject(size_t index) {
        return objects_[index]->CreateObject();
    }
    std::string GetObjectInfo(size_t index) {
        return objects_[index]->GetObjectInfo();
    }

private:
    std::vector<IObjectProxy*> objects_;
};

// This is the factory proxy template class
template<typename T>
class ObjectProxy : public IObjectProxy {
public:
    ObjectProxy() {
        ObjectFactory::Instance().AddObject(this);
    }        
    Object* CreateObject() {
        return new T;
    }
    virtual std::string GetObjectInfo() {
        return T::TalkToMe();
    };    
};

对象。h

#include <iostream>
#include "object_factory.h"
// Base object class
class Object {
public:
    virtual ~Object() {}
};
class ClassA : public Object {
public:
    ClassA() { std::cout << "ClassA Constructor" << std::endl; }
    ~ClassA() { std::cout << "ClassA Destructor" << std::endl; }
    static std::string TalkToMe() { return "This is ClassA"; }
};
class ClassB : public Object {
public:
    ClassB() { std::cout << "ClassB Constructor" << std::endl; }
    ~ClassB() { std::cout << "ClassB Destructor" << std::endl; }
    static std::string TalkToMe() { return "This is ClassB"; }
};

objects.cpp

#include "objects.h"
// Objects get registered here
ObjectProxy<ClassA> gClassAProxy;
ObjectProxy<ClassB> gClassBProxy;

main.cpp

#include "objects.h"
int main (int argc, char * const argv[]) {
    ObjectFactory& factory = ObjectFactory::Instance();
    for (int i = 0; i < factory.NumberOfObjects(); ++i) {
        std::cout << factory.GetObjectInfo(i) << std::endl;
        Object* object = factory.CreateObject(i);
        delete object;
    }
    return 0;
}

输出:

This is ClassA
ClassA Constructor
ClassA Destructor
This is ClassB
ClassB Constructor
ClassB Destructor

如果你在窗,使用C++/CLI,这变得相当容易的。。净框架提供了这种能力通过反射,它的工作很干净利落地管理的代码。

在地C++,这变得有点棘手,因为没有简单的方式来查询图书馆或应用程序的运行时的信息。有许多 框架,提供这 (只要看看海洋学委员会、迪,或者插件框架),但是最简单的手段的做自己是有一些形式的配置其中一个工厂的方法可以使用自行注册,并返回的一个执行情况的具体基类。你只是需要实现装载一个问题,并注册的工厂的方法-一旦你有,这是相当容易的。

有些东西你可以考虑的一个目计数器。这样你就不需要改变每个地方的分配,但就执行情况的定义。它是一种替代工厂的解决方案。考虑优点/缺点。

优雅的办法就是使用 CRTP:奇怪的是反复出现的模板图案.主要的例子是这样一个计数器:)

这样你就必须增加在您的具体类的执行情况:

class X; // your interface

class MyConcreteX : public counter<X>
{
    // whatever
};

当然,这是不适用的,如果使用外部实现,你不掌握。

编辑:

处理的具体问题需要有一个计数器,仅计数的第一个实例。

我2美分

有没有办法来查询该子类的一类(母语)C++。你怎么创造的实例?考虑使用工厂的方法让你迭代所有的子类。当你创建的一个实例就是这样,它不可能忘记加入一个新的子类后。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top