В моей программе есть классы 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 () не представляет особой проблемы. Но в моей реальной программе повторение одного и того же кода нецелесообразно.
Это начинает становиться грязным. Есть ли лучший способ сделать это?
Есть несколько способов справиться с проблемой:
optional<T>
который в основном связывает T
с указанием того, присутствует ли объект в действительности, имеет дело с одним специальным значением. Если выбор действительно двоичный (используйте переданную непрозрачность или объектную), это может сработать: по умолчанию будет использоваться optional<T>
указывает на то, что необязательный аргумент отсутствует и в противном случае будет использоваться его значение.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
Простой способ — использовать магическое значение:
#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;
}