Каков наилучший способ абстрагирования двух слегка отличающихся функций в c ++? - PullRequest
0 голосов
/ 27 мая 2018

Допустим, у меня есть класс, который реализует любое количество похожих методов, одного и того же типа возврата и одного и того же типа параметра для простоты.

Заголовок:

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);
}

Очень похожие методы, но различающиеся только направлением (в данном случае «Вперед» и «Вправо») в имени метода и имени одной из внутренних функций.

Что лучшеспособ абстрагировать общую родовую структуру здесь?

Ответы [ 4 ]

0 голосов
/ 27 мая 2018

Вы можете использовать диспетчеризацию тегов.

Создайте классы тегов с такими же 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() );

Если вы хотите создать больше направлений, необходим только новый класс тегакоторый реализует статическую функцию-член.

0 голосов
/ 27 мая 2018

Вы можете сделать это несколькими способами, лично я использовал подход, подобный следующему:

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();
}
0 голосов
/ 27 мая 2018

Если честно, не стоит обобщать на этом уровне алгоритма.Вы просто получаете вектор и масштабируете его с помощью константы.Если бы вы делали что-то более сложное, то это была бы другая история.Мое первое и главное предложение - пусть так и останется.

Во-вторых, если вы настаиваете на обобщении, вот оно (я предполагаю, что методы 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);
    }
};

Я предпочитаю вашеоригинальный код.

0 голосов
/ 27 мая 2018

Шаблоны не предназначены для использования при обработке разных значений (вперед, вправо), они предназначены для обработки разных типов (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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...