【问题标题】:Trouble combining GP and OOP concepts将 GP 和 OOP 概念结合起来遇到问题
【发布时间】:2012-08-11 12:30:29
【问题描述】:

我有一个带有模板化成员函数的类:

class Person
{
  template <typename TItem>
  void DoSomething(TItem item)
  {
    item.Action();
  } 
};

这允许我传递任何带有 Action 成员函数的项目,并且该人将对该项目执行该操作。所以我可以这样做:

Person person;
BaseballBat bat;
person.DoSomething(bat);

这个结构允许我用任何类型的对象调用函数。但是,如果我想存储任何类型的对象,我必须为类模板化:

template <TItem>
class Person
{
public:
  void DoSomething()
  {
    this->Item.Action();
  }

  void SetItem(TItem item)
  {
    this->Item = item;
  }
private:
  TItem Item;
};

Person<BaseballBat> person;
BaseballBat bat;
person.SetItem(&bat);
person.DoSomething();

这很烦人,因为我必须重新实例化 Person 类才能更改对象的类型。

或者,我可以从父类派生项目:

class Person
{
public:
  void DoSomething()
  {
    this->Item.Action();
  }

  void SetItem(TItem* item)
  {
    this->Item = item;
  }

private:
  ParentItem* Item;
};

class ParentItem{};

class BaseballBat : public ParentItem
{}

Person person;
BaseballBat bat;
person.SetItem(&bat);
person.DoSomething();

这很烦人,因为我必须维护所有项目的继承结构(这看起来很“非 GP”)。

当我有多层“包含对象的对象”时,问题就真的出现了——也就是说,我必须将函数模板参数从一个非常“顶级”的调用“传递”到包含的类:

class BaseballBat
{
  void DoAction();
};

class Child
{
  template <typename TItem>
  void DoAction(TItem item)
  {
    item.DoAction();
  }
};

class Person
{
  Child child;

  // This is annoying to have to pass the item to the person, who then has to pass it to the child. I'd rather "give" the child an Item, then just be able to call child.DoAction(), where the Person doesn't know anything about the item.
  template <typename TItem>
  void PlayWithChild(TItem item)
  {
    child.DoAction(item);
  }
}

谁能评论一下如何正确混合函数模板和将对象存储为成员数据这两种想法? (以上只是用来展示的俗气的例子——如果它们没有意义或者你有更好的例子,我会全神贯注:))。

--------- 编辑 --------- 也许一个更好的例子是我的真实案例的简化。 我有一个具有成员函数的类 Matcher:

template<typename TDistanceFunctor, typename TPropagationFunctor>
void Matcher::Compute(TDistanceFunctor distanceFunctor, TPropagationFunctor propagationFunctor);

然后我有另一个类 ImageAlgorithm,它使用了 Matcher:

template<typename TMatcher>
void ImageAlgorithm::Compute(TMatcher matcher)
{
  matcher.Compute(...); // How do I get the DistanceFunctor and the PropagationFunctor here?
}

我想这样称呼这些东西:

Matcher myMatcher;
.... Setup matcher (how?) ...
ImageAlgorithm algorithm;
algorithm.Compute(myMatcher);

我不知道如何通过 ImageAlgorithm 对象“通过”DistanceFunctor 和 PropagationFunctor,以便它可以到达 ImageAlgorithm::Compute 调用内部的 Matcher 对象。当然,我可以在 TDistanceFunctor 上模板 Matcher 并将 TDistanceFunctor 存储为成员变量,但后来我无法将匹配器使用的距离函子更改为不同类型的距离函子。

【问题讨论】:

    标签: c++ oop generics


    【解决方案1】:

    您可以尝试使用boost::any 来保存您的类型变量成员。

    从概述:

    boost::any 类 (...) 支持复制任何值类型并严格按照其类型安全检查提取该值。

    编辑

    您是对的,使用 boost any 调用存储的函子会出现问题。所以我建议另一种解决方案: 使用 std::function(或 boost::function)来包装你的函子。这样,Matcher 可以保存相关语法的函数对象(例如,没有参数),并且不需要在仿函数类型上进行模板化。

    函数对象已经为您完成了 OO(至少在某种意义上)和 GP 之间的组合。

    【讨论】:

    • 我从来没有真正理解 boost::any 的用处——因为如果你必须知道从 boost::any 中提取对象的类型,那么你可能只是模板化了一些东西。
    • boost::any 的想法是接口(接收值)不必知道您使用的可能的具体类型。您是对的,在此与“虚拟”没有平行关系(从某种意义上说,您可以在其上调用一个方法而无需关心底层类型)。您可以将类型 id 的映射映射到调用函数,但这会很麻烦。我添加了一个不同的解决方案。
    • 这意味着我必须为我的 Matcher 中的每个函数存储一个 std::function 对吗?这看起来很麻烦(比如 Matcher 有 5 个函数,然后另一个类似的 Propagator 有 5 个函数,我必须存储 10 个 std::functions?)
    • @DavidDoria - 是的,但由于它们各自用于其他目的,这真的有问题吗?
    • 是的。我理解你的意思是这样的:codepad.org/qS3As3s3 - 你的意思是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多