![](/img/trans.png)
[英]How To Enumerate All coclasses That Implement A Particular COM Interface?
[英]How can I keep track of (enumerate) all classes that implement an interface
我有一种情况,我有一个界面,定义某个类的行为,以填补我的程序中的某个角色,但在这个时间点,我不是100%肯定我将编写多少个类来填补该角色。 但是,与此同时,我知道我希望用户能够从GUI组合/列表框中选择实现他们想要用来填充某个角色的界面的具体类。 我希望GUI能够枚举所有可用的类,但是每当我决定实现一个新类来填充该角色时,我宁愿不必返回并更改旧代码(这可能是几个月之后)
我考虑过的一些事情:
static
列表对象,并在实现类的定义文件中添加新元素
我猜这是一个问题(或类似的问题),更有经验的程序员可能在之前(经常)遇到过,并且这种问题可能有一个共同的解决方案,这几乎肯定比任何我都好。能够想出来的。 那么,我该怎么做?
(PS我搜索过,但我发现的都是这个,而且它不一样: 我如何枚举所有实现通用接口的项目?看来他已经知道如何解决我想弄清楚的问题了。)
编辑:我将标题重命名为“我怎样才能跟踪......”,而不仅仅是“我怎么能枚举......”因为原来的问题听起来像是我对检查运行时环境更感兴趣,我在哪里真正感兴趣的是编译时簿记。
创建一个单例,您可以使用指向创建者函数的指针来注册类。 在具体类的cpp文件中,您注册每个类。
像这样的东西:
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::map
的std::string
到std::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();
};
};
objects.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
如果您使用的是Windows,并且使用的是C ++ / CLI,这就变得非常简单了。 .NET框架通过反射提供此功能,并且在托管代码中非常干净地工作。
在本机C ++中,这有点棘手,因为没有简单的方法来查询库或应用程序的运行时信息。 有许多框架可以提供这个 (只需查看IoC,DI或插件框架),但最简单的方法是自己做一些配置,工厂方法可以使用它来注册自己,并返回一个实现你的特定基类。 你只需要实现加载DLL,并注册工厂方法 - 一旦你有了它,它就相当容易了。
你可以考虑的是一个对象计数器。 这样您就不需要更改分配的每个位置,只需更改实现定义。 它是工厂解决方案的替代品。 考虑利弊。
一种优雅的方法是使用CRTP:奇怪的重复模板模式 。 主要的例子是这样一个柜台:)
这样你只需添加你的具体类实现:
class X; // your interface
class MyConcreteX : public counter<X>
{
// whatever
};
当然,如果您使用未掌握的外部实现,则不适用。
编辑:
要处理确切的问题,您需要一个只计算第一个实例的计数器。
我的2美分
无法在(本机)C ++中查询类的子类。 你如何创建实例? 考虑使用工厂方法,允许您迭代您正在使用的所有子类。 当您创建这样的实例时,以后不可能忘记添加新的子类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.