我有很多类,都有完全相同的界面。这个接口定义了一些方法,其中一些是模板化的(类本身可能是也可能不是)。
所以界面看起来像这样
class MyClass
{
public:
void Func1();
template <typename T>
void Func2(T param);
};
我有许多函数可以使用符合此接口的各种对象,但希望避免在编译时知道确切的实现。
显然,默认的C ++解决方案是拥有一个所有这些类派生的基类型,并传递指向它的指针并让多态实现所有工作。
问题是模板化成员函数不能是虚拟的,因此无法使用此方法。我还想避免更改跟随此接口的当前类集,因为它们有很多,其中一些是在我的项目范围之外定义的。
另一个解决方案是模拟使用这些对象的函数,以便它们专门用于正确的类型。这可能是一个解决方案,但由于遗留的要求模板化,大量的功能可能是不可能的(这是我无法做任何事情,因为客户端代码不是我负责的事情。)
我最初的想法是提供某种类型为中性的载体类,并且在效果中包含公共接口,并且有一个基本接口类来传递内部类型。
的内容
class MyInterface
{
public:
virtual void Func1() = 0;
};
template <typename T>
class MyImplementation
{
public:
virtual void Func1()
{
m_impl->Func1();
}
private:
T* m_impl;
};
但是,模板化的成员函数似乎也阻止了这种方法。
我查看了boost :: any和boost :: function类,我认为它们可能会提供某种解决方案,但它们似乎没有给我正确答案。
那么,有没有人有任何建议或解决如何使这成为可能,如果确实如此?就个人而言,我倾向于模拟需要这些对象的各种功能 - 因为这是功能模板提供的 - 但认为值得首先进行调查。
提前致谢
答案 0 :(得分:2)
我不完全清楚你是如何将参数T解析为Func2的,你是否需要某种动态调度,或者在编译时在呼叫站点知道它?
在前一种情况下,它听起来像多方法。在后者中,您的界面想法如何变化:
#include <iostream>
template<class T> struct generic_delegate
{
virtual void call(T param) = 0;
};
template<class U, class T> class fn_delegate : public generic_delegate<T>
{
U* obj;
void (U::*fn)(T);
public:
fn_delegate(U* o, void (U::*f)(T)) :
obj(o), fn(f)
{}
virtual void call(T param)
{
(obj->*fn)(param);
}
};
class A
{
public:
template<class T> void fn(T param)
{
std::cout << "A: " << param << std::endl;
}
};
class B
{
public:
template<class T> void fn(T param)
{
std::cout << "B: " << param << std::endl;
}
};
template<class T, class U> generic_delegate<T>* fn_deleg(U* o)
{
return new fn_delegate<U, T>(o, &U::template fn<T>);
}
int main()
{
A a;
B b;
generic_delegate<int>* i = fn_deleg<int>(&a);
generic_delegate<int>* j = fn_deleg<int>(&b);
i->call(4);
j->call(5);
}
显然,你要传递的是泛型委托指针。
答案 1 :(得分:1)
如果您使用模板,则需要了解AT COMPILE TIME您正在使用的类型。这只是模板的本质(模板看起来像是在运行时动态的代码,但实际上它只是简写,它告诉编译器要编译的函数的哪个版本并包含在目标代码中)。最佳案例Senario是这样的:
template <class T>
void DoSomethingWithMyInterface(MyInterface<T> X)
{
//do something
}
...
switch (MyObject.GetTypeCode())
{
case TYPE1: DoSomethingWithMyInterface<type1>(MyObject); break;
case TYPE2: DoSomethingWithMyInterface<type2>(MyObject); break;
case TYPE3: DoSomethingWithMyInterface<type3>(MyObject); break;
case TYPE4: DoSomethingWithMyInterface<type4>(MyObject); break;
}
我实际上经常使用这种情况。我编写了模板化的c ++代码,用于处理动态类型语言。这意味着顶级语言直到运行时才知道数据类型,但我需要在编译时知道它们。所以我创建了这个“TypeSwitch”(我实际上有一个花哨的可重用的)。这将查看运行时的数据类型,然后确定要运行的已编译模板函数。
注意 - 这需要我知道我之前要支持的所有类型(我这样做),并且switch语句实际上会导致编译器生成所有可能执行的代码。然后在运行时选择正确的。