我可能会以完全错误的方式解决这个问题,但它已经迟到了,它让我有点疯狂。
我的基类中有一个函数,它允许我创建派生类的新对象。然而,如果它说混战,我希望它可以与我的其他派生类互换。我无法计算如何传入不同的类,因此它将创建该类的对象。
void BaseUnit::CreateNewUnit(vector<BaseUnit*>& MyVector)
{
UnitID++;
MyVector.push_back(new Melee());
}
答案 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);
}
按键时调用上述功能,如果按下某个键,则创建一个新的派生对象并调用你的函数:
近战* 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,它不应该是您传递的参数,而是您游戏类的本地成员,您可以直接访问它而无需将其作为参数
另外,遵循正确的编码约定,不要使用成员方法或对象或大写参数。这简直令人困惑。