2010-07-19 110 views
2

我有一些类,所有的接口都完全相同。这个接口定义了一些方法,其中一些是模板化的(类本身可能会或可能不会)。使用相同的接口传递不同类型的对象

所以界面看起来像这样

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

你真的想解决什么问题? – 2010-07-19 14:45:20

+0

我有很多函数采用符合这个接口的各种对象,但是想避免在编译时需要知道确切的实现。 – 2010-07-19 14:57:40

+0

您可以尝试检查有关您的主要问题的问题:如何解决虚拟模板功能问题。我知道我之前看到过这个问题。我不确定你是否会在那里找到你的解决方案,但这将是一个好的开始。 – n1ckp 2010-07-19 15:09:05

回答

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

如果你使用,你需要知道的模板你正在使用的类型编译时间。这就是模板的本质(模板看起来像是在运行时是动态的代码,但实际上它只是速记,告诉编译器编译哪些版本的函数并将其包含在目标代码中)。最好的情况下西安娜是这样的:

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语句实际上导致编译器生成所有可执行的代码。然后在运行时选择正确的一个。

+0

这是一个有趣的解决方案,我认为可以解决这种情况下的问题。客户端正在处理各种对象的一小部分,不需要大量的switch语句。 – 2010-07-19 15:25:55

相关问题