动态构建功能

Iur*_*nyi 4 c++ function

我担心在这个网站的某个地方会回答这样的事情,但我找不到它,因为我甚至不知道如何制定这个问题.所以这就是问题所在:

我有一个体素投掷功能.首先,我计算偏移,角度和东西,然后我做了瞌睡.但是我为每个函数制作了几个版本,因为有时我想复制像素,有时是blit,有时为每个像素点亮3*3平方以获得平滑效果,如果对象调整大小,有时只是将像素复制到屏幕上的n*n像素.功能中心的那个小部分有很多版本.

我可以做什么而不是编写10个仅仅由代码的中心部分不同的相同功能?出于性能原因,将函数指针作为参数传递不是一种选择.我不确定让他们内联会做的伎俩,因为我发送的参数不同:有时我计算体积(Z值),有时我知道像素是从下到上绘制的.

我假设有一些方法可以在C++中使用每个人都知道的东西.请告诉我学习这项工作需要学习的内容.谢谢.

Use*_*ess 7

传统的OO方法是模板方法模式策略模式.

模板方法

第一个是Vincenzo的答案中描述的技术的扩展:您不是编写简单的非虚拟包装器,而是编写包含整个算法的非虚函数.那些可能不同的部分是虚函数调用.给定实现所需的特定参数存储在提供该实现的派生类对象中.

例如.

class VoxelDrawer {
protected:
  virtual void copy(Coord from, Coord to) = 0;
  // any other functions you might want to change
public:
  virtual ~VoxelDrawer() {}
  void draw(arg) {
    for (;;) {
      // implement full algorithm
      copy(a,b);
    }
  }
};
class SmoothedVoxelDrawer: public VoxelDrawer {
  int radius; // algorithm-specific argument
  void copy(Coord from, Coord to) {
    blit(from.dx(-radius).dy(-radius),
         to.dx(-radius).dy(-radius),
         2*radius, 2*radius);
  }
public:
  SmoothedVoxelDrawer(int r) : radius(r) {}
};
Run Code Online (Sandbox Code Playgroud)

战略

这是类似的,但不是使用继承,而是将多态Copier对象作为参数传递给函数.它更灵活,它将您的各种复制策略与特定功能分离,您可以在其他功能中重复使用复制策略.

struct VoxelCopier {
  virtual void operator()(Coord from, Coord to) = 0;
};
struct SmoothedVoxelCopier: public VoxelCopier {
  // etc. as for SmoothedVoxelDrawer
};

void draw_voxels(arguments, VoxelCopier &copy) {
  for (;;) {
    // implement full algorithm
    copy(a,b);
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然比传入函数指针更整洁,但模板方法和策略都不可能具有比传递函数指针更好的性能:运行时多态仍然是间接函数调用.

政策

策略模式的现代C++等价物是策略模式.这简单地将运行时多态性替换为编译时多态,以避免间接函数调用和启用内联

// you don't need a common base class for policies,
// since templates use duck typing
struct SmoothedVoxelCopier {
  int radius;
  void copy(Coord from, Coord to) { ... }
};
template <typename CopyPolicy>
void draw_voxels(arguments, CopyPolicy cp) {
  for (;;) {
    // implement full algorithm
    cp.copy(a,b);
  }
}
Run Code Online (Sandbox Code Playgroud)

因为类型扣除,你可以简单地打电话

draw_voxels(arguments, SmoothedVoxelCopier(radius));
draw_voxels(arguments, OtherVoxelCopier(whatever));
Run Code Online (Sandbox Code Playgroud)

NB.我在这里略微不一致:我曾经operator()让我的策略调用看起来像常规函数,但是我的策略的常规方法.只要你选择一个并坚持下去,这只是一个品味问题.

CRTP模板方法

有一个最终机制,它是模板方法的编译时多态版本,并使用奇怪的重复模板模式.

template <typename Impl>
class VoxelDrawerBase {
protected:
  Impl& impl() { return *static_cast<Impl*>(this); }

  void copy(Coord from, Coord to) {...}
  // *optional* default implementation, is *not* virtual
public:
  void draw(arg) {
    for (;;) {
      // implement full algorithm
      impl().copy(a,b);
    }
  }
};
class SmoothedVoxelDrawer: public VoxelDrawerBase<SmoothedVoxelDrawer> {
  int radius; // algorithm-specific argument
  void copy(Coord from, Coord to) {
    blit(from.dx(-radius).dy(-radius),
         to.dx(-radius).dy(-radius),
         2*radius, 2*radius);
  }
public:
  SmoothedVoxelDrawer(int r) : radius(r) {}
};
Run Code Online (Sandbox Code Playgroud)

摘要

一般来说,我更喜欢策略/策略模式的低耦合和更好的重用,并且只选择模板方法模式,只有在你参数化的顶级算法真正一成不变的时候(即,当你要么重构时)现有的代码或者真的确定你对变异点的分析)并且重用真的不是问题.

如果存在多个变异轴(也就是说,您有多个方法copy,并且希望独立地改变它们的实现),那么使用模板方法也非常痛苦.您要么最终得到代码重复或mixin继承.