在c ++中抽象两个略有不同的函数的最佳方法是什么?

时间:2018-05-26 22:28:52

标签: c++ templates

假设我有一个类,它实现了许多类似的方法,相同的返回类型和相同的参数类型,以保持简单。

部首:

protected:
  void MoveForward(float Magnitude);
  void MoveRight(float Magnitude);

实现:

void MyCharacter::MoveForward(float Magnitude) {
  AddMovementInput(GetActorForwardVector() * Magnitude);
}

void Myharacter::MoveRight(float Magnitude) {
  AddMovementInput(GetActorRightVector() * Magnitude);
}

非常相似的方法,但只是方法名称中的方向(在本例中为Forward和Right)以及其中一个内部函数的名称不同。

在这里抽象通用通用结构的最佳方法是什么?

4 个答案:

答案 0 :(得分:3)

您可以通过多种方式进行此操作,我个人使用了与以下类似的方法:

enum class Direction { LEFT, RIGHT, TOP, BOTTOM };

class MyCharacter {
   template<Direction DIR> Vector MyCharacter::getVector() const;

   template<Direction DIR> void move() {
     AddMovementInput(getVector<Dir>() * magnitude);
   }
}

template<> Vector MyCharacter::getVector<Direction::LEFT>() const { ... }
template<> Vector MyCharacter::getVector<Direction::RIGHT>() const { ... }

当然你可以在没有模板的情况下做同样的事情,但我想你知道你在做什么,如果你特别需要它们。

请注意,您可以直接将该函数作为模板参数传递,但我发现它不太清楚,例如:

float GetActorForwardVector() { return 3.0f; }

class Foo
{
public:
  template<float (*F)()> float move() { return F(); }
  inline float moveLeft() { return move<GetActorForwardVector>(); }
};

int main()
{
  Foo foo;
  std::cout << foo.moveLeft();
}

答案 1 :(得分:2)

说实话,你不应该在这个级别的算法上进行概括。你只需要一个向量并用常量来缩放它。如果你正在做一些更复杂的事情,那么这将是另一个故事。我的首要建议就是让它保持这种状态。

其次,如果你坚持在这里推广它(我假设GetXVector方法是类成员):

class Foo
{
protected: 
    void MoveForward(float x) { Move(&Foo::GetActorForwardVector, x); }
    void MoveRight(float x) { Move(&Foo::GetActorRightVector, x); }
private:
    template<typename GetDirectionFunc>
    void Move(GetDirectionFunc getDirection, float x)
    {
        AddMovementInput((this->*getDirection)() * x);
    }
};

我更喜欢您的原始代码。

答案 2 :(得分:1)

您可以使用tag-dispatching。

使用相同的static成员函数创建标记类,以实现特定的行为:

namespace Direction {
struct Forward
{
    static Vector actorVector() { return GetActorForwardVector(); }
};

struct Right
{
    static Vector actorVector() { return GetActorRightVector(); }
};
} // namespace Direction

在您的课程中,实现一个模板move函数,该函数接受Direction类的实例,但不使用它。相反,它调用标记类的static成员函数。

class MyCharacter
{
public:

    template< typename Direction >
    void move( const float magnitude, const Direction )
    {
        AddMovementInput( Direction::actorVector() * magnitude );
    }
};

用法示例:

MyCharacter mc;

mc.move( 10.0, Direction::Forward() );

如果要创建更多方向,则只需要一个实现静态成员函数的新标记类。

答案 3 :(得分:0)

当您处理不同的值(向前,向右)时,不打算使用模板,它们意味着处理不同的类型(int,double)。 您可以使用一个带参数的通用Move函数:

void Move(int x, int y);

// Move forward
Move (0, 1);

// Move right
Move (1, 0);

您可以使用函数指针在结构中组合移动方向和相应的函数:

struct MOVE_INFO
{
    int x;
    int y;
    void (*GetVector)(void);
}

void Move(MOVE_INFO mv)
{
    ...
    mv.GetVector();
    ...
}

main()
{
    MOVE_INFO forward = {0, 1, SomeLib::GetForwardVector};
    MOVE_INFO right = {1, 0, SomeLib::GetRightVector};

    // Move Forward
    Move(forward);

    // Move Right
    Move(right);
}