c ++将不同的类传递给函数

时间:2015-04-11 20:56:20

标签: c++ inheritance vector

我可能会以完全错误的方式解决这个问题,但它已经迟到了,它让我有点疯狂。

我的基类中有一个函数,它允许我创建派生类的新对象。然而,如果它说混战,我希望它可以与我的其他派生类互换。我无法计算如何传入不同的类,因此它将创建该类的对象。

void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector)
{
    UnitID++;
    MyVector.push_back(new Melee());

}

5 个答案:

答案 0 :(得分:1)

您可以使用“prototype design pattern”。

加入std::map关联键 - &gt;原型并且您已完成:当用户按下某个键时,您将查找地图,提取原型并将其传递给CreateNewUnit。在CreateNewUnit中,您将使用Prototype::Clone()

class BaseUnit
{
public:
    ... // your methods
    virtual BaseUnit* Clone() = 0;
};

class Melee : public BaseUnit
{
public:
    BaseUnit* Clone() { return new Melee(); }
};

void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector, BaseUnit* prototype )
{
    UnitID++;
    MyVector.push_back( prototype -> Clone() );
}

int main()
{
    std::map< char, BaseUnit* > prototypes;
    prototypes[ 'a' ] = new Melee();
    prototypes[ 'b' ] = new OtherUnit();
    ...

    std::vector< BaseUnit* > units;

    char selection = GetKeyPressed();
    BaseUnit::CreateNewUnit( units, prototypes[ selection ] );
}

此解决方案的好处是,当您需要在应用程序中添加新的单元类型时,您只需在原型图中添加一个新条目。

顺便说一下:如果从BaseUnit派生的类在全局“原型”地图中注册,那么只需稍加努力就可以避免这种情况。

答案 1 :(得分:0)

这可能会让你知道如何做到这一点: 1.更改函数签名以包含派生对象指针作为第二个参数

void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector, const BaseUnit* derived) {
    UnitID++;
    MyVector.push_back(derived);
}
  1. 按键时调用上述功能,如果按下某个键,则创建一个新的派生对象并调用你的函数:

    近战* m =新近战();

    unit.CreateNewUnit(myVector,M);

答案 2 :(得分:0)

我要将指针传递给单位:

void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector, BaseUnit* unit)
{
    UnitID++;
    MyVector.push_back(unit);
}

或传递按下的键或其他ID:

void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector, char type)
{
    switch(type) //this would be the key pressed
    {
    case '1':
         MyVector.push_back(new Melee());
         UnitID++;
         break;//this would be continued for all possible units
    }
}

答案 3 :(得分:0)

如果要在编译时确定它,可以使用模板方法或为每个类创建方法。这称为工厂方法,它是一种设计模式。请注意,此处工厂的“提示”是模板参数。

如果您希望在运行时确定它,您需要以某种方式识别相关的类,即工厂的“提示”。大多数情况下,这将是一个枚举或字符串。再次,阅读工厂设计模式和工厂方法。

答案 4 :(得分:-1)

如果在编译时需要,可以直接找工厂模板。如果不同的类具有需要传递的不同参数,则应使用可变参数模板:

#include <utility> 

class Factory {
    ...
    template <typename Derived, typename ...Args>
    BaseUnit * create(Args &&... args)
    { 
        return new Derived(std::forward<Args>(args)...);
    }
};

然后你可以简单地创建一个工厂并调用factory.create(Melee, optional_arguments)或任何类型,并创建一个模板专门化来使用提供的参数实例化该特定类型。

如果您需要&#34;运行时调度&#34;创建函数,您可以在enum Type中添加类似BaseUnit的内容,或列出每种可能的派生类型的其他ID,并使用create(BaseUnit::Type type)语句和switch (type)语句创建适当类型的每个对象类型的大小写。当然,这可以与上面列出的模板工厂一起使用。

一个开关语句将比一个地图更有效率,而且,如果一个地图被填充并静态地#34;它就没有意义。只有在运行时注册新的对象创建方法时,映射才有意义。在这种情况下,您可以拥有一个类型id的映射和一个指向函数的指针,返回一个新的BaseType派生。这样,您可以注册从动态库加载的额外函数,根据类型ID查找函数指针,并使用它来实例化该类型的对象。但这只是在你需要运行时注册的情况下。否则坚持以前的解决方案。如果您有类似&#34;插件&#34;这样的话,那将是合理的。 - 动态库,提供一组额外的类型和创建它们的适当函数,因此您可以加载库,在映射中注册其组件,并能够实例化在&#34实现期间不存在的类型核心逻辑&#34;游戏当然,这一切都必须依赖于核心逻辑设计的多态接口才能工作,否则就不会失败。此外,对于此解决方案,您可能希望id是字符串而不是整数,因为它提供了更大的灵活性,并且没有switch语句的限制。

另请注意,我没有包含您的vector<BaseUnit*>& MyVector - IMO,它不应该是您传递的参数,而是您游戏类的本地成员,您可以直接访问它而无需将其作为参数

另外,遵循正确的编码约定,不要使用成员方法或对象或大写参数。这简直令人困惑。