Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用同一接口传递不同类型的对象_C++_Templates - Fatal编程技术网

C++ 使用同一接口传递不同类型的对象

C++ 使用同一接口传递不同类型的对象,c++,templates,C++,Templates,我有许多类,它们都具有完全相同的接口。这个接口定义了一些方法,其中一些是模板化的(类本身可能是,也可能不是) 所以界面看起来像这样 class MyClass { public: void Func1(); template <typename T> void Func2(T param); }; class-MyClass { 公众: void Func1(); 模板 无效函数2(T参数); }; 我有许多函数,它们接受符合此接口的各种对象,但不想在编译时知道确切

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

所以界面看起来像这样

class MyClass
{
public:
  void Func1();

  template <typename T>
  void Func2(T param);
};
class-MyClass
{
公众:
void Func1();
模板
无效函数2(T参数);
};

我有许多函数,它们接受符合此接口的各种对象,但不想在编译时知道确切的实现

显然,默认的C++解决方案是有一个基类,所有这些类都是从一个指针派生的,并通过一个指针,并且多态性完成了所有的工作。 问题是模板成员函数不能是虚拟的,因此无法使用此方法。我还希望避免更改遵循此接口的当前类集,因为其中有大量类,其中一些是在我的项目范围之外定义的

另一个解决方案是对使用这些对象的函数进行模板化,以便它们专门用于正确的类型。这可能是一个解决方案,但由于遗留需求,模板化大量函数可能是不可能的(这是我不能做的事情,因为客户端代码不是我的责任)

我最初的想法是提供某种类型的carrier类,它与类型无关,实际上在这里包装了公共接口,并有一个基本接口类来传递内部类型

类似于

class MyInterface
{
public:   
 virtual void Func1() = 0;
};

template <typename T>
class MyImplementation
{
public:
  virtual void Func1()
  {
    m_impl->Func1();
  }

private:
  T* m_impl;
};
类MyInterface
{
公众:
虚空Func1()=0;
};
模板
类My实现
{
公众:
虚空Func1()
{
m_impl->Func1();
}
私人:
T*m_impl;
};
但模板成员函数似乎再次阻止了这种方法

我看了boost::any和boost::function类,我认为它们可能提供某种解决方案,但它们似乎没有给我正确的答案

那么,是否有人对如何使这成为可能提出了任何建议或努力,如果确实是这样的话?就我个人而言,我倾向于对需要这些对象的各种功能进行模板化——因为这是模板提供的功能——但我认为首先值得研究一下


提前感谢

如果您使用模板,您需要在编译时知道您使用的是哪种类型。这就是模板的本质(模板看起来像是运行时动态的代码,但实际上只是告诉编译器要编译并包含在目标代码中的函数版本的简写)。最佳案例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;
}
模板
void DoSomethingWithMyInterface(MyInterface X)
{
//做点什么
}
...
开关(MyObject.GetTypeCode())
{
案例类型1:DoSomethingWithMyInterface(MyObject);中断;
案例类型2:DoSomethingWithMyInterface(MyObject);中断;
案例类型3:DoSomethingWithMyInterface(MyObject);中断;
案例类型4:DoSomethingWithMyInterface(MyObject);中断;
}
实际上我经常使用这种情况。我编写模板C++代码,它对动态类型的语言进行处理。这意味着顶级语言直到运行时才知道数据类型,但我需要在编译时知道它们。所以我创建了这个“类型开关”(实际上我有一个奇特的可重复使用的)。这将在运行时查看数据类型,然后确定要运行哪些已编译的模板函数


注意——这要求我事先知道要支持的所有类型(我也知道),switch语句实际上会使编译器生成所有可能执行的代码。然后在运行时选择正确的参数。

我不完全清楚的是如何将参数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);
}
#包括
模板结构泛型委托
{
虚空调用(T参数)=0;
};
模板类fn\u委托:公共泛型\u委托
{
U*obj;
无效(U::*fn)(T);
公众:
fn_代表(U*o,void(U::*f)(T)):
obj(o),fn(f)
{}
虚拟无效调用(T参数)
{
(obj->*fn)(参数);
}
};
甲级
{
公众:
模板无效fn(T参数)
{

你到底想解决什么问题?我有很多函数,它们接受符合此接口的各种对象,但不想在编译时知道具体的实现。你可以试着检查一下你的主要问题:如何解决虚拟模板函数问题。我知道我以前见过几次这样的问题。我不确定你是否会在那里找到你的解决方案,但这将是一个好的开始。我已经有了一个很好的外观,大多数答案都是非常标准的,并且是我试图避免的-将对象或模板作为类而不是函数的模板函数-试图避免这些,因为接口已经在使用,我不希望客户端因此不得不修改代码。这是一个很长的问题,但值得一问。为什么不让一个虚拟函数调用模板函数呢?这是一个有趣的解决方案,我认为在这种情况下可能会解决这个问题。客户端正在处理一小部分不需要大量switch语句的各种对象。