使用相同的接口传递不同类型的对象

时间:2010-07-19 14:28:31

标签: c++ templates

我有很多类,都有完全相同的界面。这个接口定义了一些方法,其中一些是模板化的(类本身可能是也可能不是)。

所以界面看起来像这样

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类,我认为它们可能会提供某种解决方案,但它们似乎没有给我正确答案。

那么,有没有人有任何建议或解决如何使这成为可能,如果确实如此?就个人而言,我倾向于模拟需要这些对象的各种功能 - 因为这是功能模板提供的 - 但认为值得首先进行调查。

提前致谢

2 个答案:

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