0

我的程序有一个 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() 的不同调用重复相同的代码并不是什么大问题。但是在我的实际程序中,重复所有相同的代码是不切实际的。

这开始变得混乱了。有没有更好的方法来解决这个问题?

4

2 回答 2

2

一种简单的方法是使用魔法值:

#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;
}
于 2012-11-12T01:53:07.997 回答
0

有几种方法可以解决这个问题:

  1. 正如另一个答案中指出的那样,您可以使用特殊值来指示应该使用默认值。如果数据类型支持明显的特殊值,这可能是正确的解决方案,但它不适用于所有类型,并且实际上相对难以维护。我在生产代码中看到了“不可能”值最终成为可能的情况,从而导致未定义的行为(例如,债券的收益率被认为始终为正,但事实证明债券的收益率可能为负)。
  2. 使用optional<T>基本上将 aT与对象是否实际存在的指示捆绑在一起处理一个特殊值。如果选择确实是二进制的(使用传递的不透明度或对象的不透明度),这可以工作:默认值将使用optional<T>指示可选参数不存在,否则将使用其值。
  3. 一个更具可扩展性的版本是传递一个函数,该函数通过在对象上调用它来确定对象的不透明度Carstd::function<double(Car const&)>. 默认值是获取Car's opacity 的函数,但也可以是其他函数,包括始终返回一个常量。

Since the third option is a bit more obscure I'll provide an example below (which assumes that the Car has a member function opacity() returning the Car's opacity):

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

It is now easy to pass in other function objects somehow copying the opacity:

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
于 2012-11-12T02:19:28.780 回答