c++将不同的类传递到函数中

c++ pass different classes into function

本文关键字:函数 c++      更新时间:2023-10-16

我可能完全错了方向,但已经晚了,这让我有点生气。

我的基类中有一个函数,它应该允许我创建派生类的新对象。然而,在它说Melee的地方,我希望它可以与我的其他派生类互换。我不知道如何传入不同的类,所以它会创建该类的对象。

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

您可以使用"原型设计模式"。

std::map中放入associations键->prototype,就完成了:当用户按下某个键时,您可以查找映射,提取原型并将其传递给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派生的类在全局"原型"映射中注册,只需付出一点努力,您甚至可以避免这种情况。

我要么将指针传递给单元:

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
}
}

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

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

这可能会让您了解如何做到这一点:1.改变函数签名以包括导出的对象指针作为第二参数

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

    Melee*m=新Melee();

    unit.CreateNewUnit(myVector,m);

如果在编译时需要,您可以简单地使用工厂模板。如果不同的类有不同的参数需要传递,您应该使用一个可变模板:

#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)或任何类型,然后将创建一个模板专门化,用提供的参数实例化该特定类型。

如果您需要一个"运行时调度"创建函数,您可以在BaseUnit中有一个类似enum Type的东西,或者有一个列出所有可能派生类型的其他id,并有一个create(BaseUnit::Type type)方法,该方法带有switch (type)语句,每个对象类型都有一个case,用于创建适当的类型。当然,这可以与上面列出的模板工厂结合使用。

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

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

此外,请遵循适当的编码约定,不要使用成员方法、对象或参数的大写字母。这只是令人困惑。