Вызовите родительский конструктор с разными аргументами в зависимости от аргумента дочернего конструктора - PullRequest
0 голосов
/ 28 октября 2018

Есть ли способ вызвать родительский конструктор с разными аргументами в зависимости от значения аргумента, который имеет дочерний конструктор?

У меня есть следующий родительский класс:

class Rectangle
{
public:
    Rectangle(std::string name, glm::vec3 top_left_corner, float height, float width, glm::vec3 color, bool fill);
    ~Rectangle();
    //...
}

И дочерний класс:

class Wall :
    public Rectangle
{
public:
    Wall(std::string name, Position position, float scene_height, float scene_width, float thickness, glm::vec3 color);
    ~Wall();
    //...
}

Где Position - это enum, который должен определять, с какими аргументами должен вызываться родительский конструктор:

enum Position { UP, DOWN, LEFT, RIGHT };

Так что в основном я быхотелось бы иметь что-то вроде этого в дочернем конструкторе:

Wall::Wall(std::string name, Position position, float window_height, float window_width, float thickness, glm::vec3 color) {
    switch(position) {
    case UP:
        Rectangle(name, glm::vec3(0, window_height, 0), thickness, window_height, color, true);
        break;
    case DOWN:
        Rectangle(name, glm::vec3(0, thickness, 0), thickness, window_width, color, true);
        break;
    case LEFT:
        Rectangle(name, glm::vec3(0, window_height, 0), window_height, thickness, color, true);
        break;
    case RIGHT:
        Rectangle(name, glm::vec3(0, window_width - thickness, window_height), window_height, thickness, color, true);
        break;
    }
}

Но, как вы знаете, я должен сначала вызвать родительский конструктор, например:

Wall::Wall(std::string name, Position position, float window_height, float window_width, float thickness, glm::vec3 color)
    : Rectangle(name, glm::vec3(0, window_width - thickness, window_height), window_height, thickness, color, true) {}

И это неДай мне много свободы.Каким будет хороший объектно-ориентированный подход?

Ответы [ 4 ]

0 голосов
/ 28 октября 2018

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

Вы можете изменить top_left_corner с помощью enum и затем вычислить его внутриконструктор.

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

0 голосов
/ 28 октября 2018

Создать фабричный метод:

Rectangle MakeRectangle(const std::string& name,
                        const Position& position,
                        float window_height, float window_width,
                        float thickness,
                        const glm::vec3& color)
{
    switch(position) {
    case UP:
        return Rectangle(name,
                         glm::vec3(0, window_height, 0),
                         thickness,
                         window_height,
                         color,
                         true);
    case DOWN:
        return Rectangle(name,
                         glm::vec3(0, thickness, 0),
                         thickness,
                         window_width,
                         color,
                         true);
    case LEFT:
        return Rectangle(name,
                         glm::vec3(0, window_height, 0),
                         window_height,
                         thickness,
                         color,
                         true);
    case RIGHT:
        return Rectangle(name,
                         glm::vec3(0, window_width - thickness,  window_height),
                         window_height,
                         thickness,
                         color,
                         true);
    }
    throw std::runtime_error("Invalid position");
}

Тогда

Wall::Wall(std::string name,
           Position position,
           float window_height, float window_width,
           float thickness,
           glm::vec3 color)
: Rectangle(MakeRectangle(name, position, window_height, window_width, thickness, color)){
// ...
}
0 голосов
/ 28 октября 2018

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

class Wall {
  private:
  static glm::vec3 top_left_corner(Position position, float window_height, float window_width, float thickness) {
    switch (position) {
      case UP: return glm::vec3(0, window_height, 0);
      case DOWN: return glm::vec3(0, thickness, 0);
      case LEFT: return glm::vec3(0, window_height, 0);
      case RIGHT: return glm::vec3(0, window_width - thickness, window_height);
    }  
  }

  // similary for other arguments

И затем вы можете вызвать ваш конструктор следующим образом:

Wall::Wall(std::string name, Position position, float window_height, float window_width, float thickness, glm::vec3 color)
: Rectangle(name,
    top_left_corner(position, window_height, window_width, thikness),
    ....... /* other arguments */
) {}
0 голосов
/ 28 октября 2018

Я не знаю, что такое хороший ООП-подход, но я знаю, как это сделать в C++ во время компиляции, если это то, что вам нужно.

template <class T, T val>
struct constant
{
#if __cplusplus >= 201703L
    constexpr const static inline T value = val;
#else
    constexpr const static T value = val;
#endif
};

class Wall: public Rectangular
{
    Wall(..., constant<Position, Position::UP>, ...):
        Rectangular(...) {}
    // Providing other overload to initialize your base code differently
};

Редактировать:

На самом деле, в вашем случае, вы можете заменить класс constant на std::integral_constant для удобства.

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