дизайн класса перегрузки функций

В моей программе есть классы Car и CarManager, которые выглядят примерно так:

#include <list>

class Car
{
public:
void Draw() { Draw(m_opacity); }
void Draw(float opacity)
{
}

private:
float m_opacity;
};

class CarManager
{
public:
//Draw cars using their m_opacity member
void DrawCars()
{
for(auto i = m_cars.begin(); i != m_cars.end(); i++)
i->Draw();
}

//Draw cars using opacity argument
void DrawCars(float opacity)
{
for(auto i = m_cars.begin(); i != m_cars.end(); i++)
i->Draw(opacity);
}

private:
std::list<Car> m_cars;
}

MyApplication::OnRender()
{
CarManager* pCarManager = GetCarManager();

//If this condition is met, I want all cars to be drawn with 0.5 opacity.
if(condition)
pCarManager->DrawCars(0.5f);

//Otherwise, draw cars using their m_opacity value.
else
pCarManager->DrawCars();
}

C ++ не позволяет использовать нестатический член в качестве аргумента по умолчанию, поэтому я перегружен функциями рисования. Если аргумент не предоставлен, перегруженная версия функции будет вызвана с использованием члена класса.

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

В этом примере код рендеринга в CarManager :: DrawCars () довольно маленький, поэтому повторение того же кода с другим вызовом Car :: Draw () не представляет особой проблемы. Но в моей реальной программе повторение одного и того же кода нецелесообразно.

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

0

Решение

Есть несколько способов справиться с проблемой:

  1. Как было указано в другом ответе, вы можете использовать специальное значение, чтобы указать, что следует использовать значение по умолчанию. Если тип данных поддерживает очевидное специальное значение, это может быть правильным решением, но оно не работает со всеми типами и на самом деле относительно сложно поддерживать. В производственном коде я видел случаи, когда «невозможное» значение в конечном итоге становилось возможным, что приводило к неопределенному поведению (например, доходность по облигациям считалась всегда положительной, но оказывается, что облигации могут иметь отрицательную доходность).
  2. Используя optional<T> который в основном связывает T с указанием того, присутствует ли объект в действительности, имеет дело с одним специальным значением. Если выбор действительно двоичный (используйте переданную непрозрачность или объектную), это может сработать: по умолчанию будет использоваться optional<T> указывает на то, что необязательный аргумент отсутствует и в противном случае будет использоваться его значение.
  3. Более масштабируемой версией является передача функции, которая определяет непрозрачность объекта, вызывая его на Car объект: std::function<double(Car const&)>, По умолчанию будет функция, которая получает CarНепрозрачность, но это может быть какая-то другая функция, в том числе всегда возвращать константу.

Поскольку третий вариант немного более неясен, я приведу пример ниже (который предполагает, что Car имеет функцию-член opacity() возвращая Carнепрозрачность):

void Car::Draw(std::function<double(Car const&)> getOpacity
= std::mem_fn(&Car::opacity)) {
opacity = getOpacity(*this);
// ...
}

Теперь легко передать другие функциональные объекты, копируя непрозрачность:

double ConstantOpacity(Car const&, double value) { return value; }
double ComputeOpacity(Car const& c, double value) { return (c.opacity() + value) / 2; }

Car* car = ...;
car->Draw(std::bind(&Car::opacity, _1));        // use the car's opacity
car->Draw(std::bind(&ConstantOpacity, _1, 0.5); // use opacity 0.5
car->Draw(std::bind(&ComputeOpacity, _1, 0.5);  // average of the car's opacity and 0.5
0

Другие решения

Простой способ — использовать магическое значение:

#include <list>

class Car
{
public:
static float noOpacity() { return -1; }

void Draw(float opacity)
{
if (opacity==noOpacity()) {
opacity = m_opacity;
}
// etc.
}

private:
float m_opacity;
};

class CarManager
{
public:
//Draw cars using optional opacity argument
void DrawCars(float opacity = Car::noOpacity(); )
{
for(auto i = m_cars.begin(); i != m_cars.end(); i++)
i->Draw(opacity);
}

private:
std::list<Car> m_cars;
}
2

По вопросам рекламы [email protected]