我有DBGameAction和ServerGameAction类,它们有共同的父类GameAction。类DBGameAction和ServerGameAction它是一个安全的API,用于从程序的不同部分使用实体GameAction。
我的问题是:首先创建DBGameAction实体然后将其转换为ServerGameAction实体是否正常?或者它可能是一个错误的程序设计?
我的节目:
#include <vector>
#include <string>
#include <iostream>
class GameAction
{
protected:
/* Need use mutex or something else for having safety access to this entity */
unsigned int cost;
unsigned int id;
std::vector<std::string> players;
GameAction(){}
public:
unsigned int getCost() const
{
return cost;
}
};
class DBGameAction : public GameAction
{
public:
void setCost(unsigned int c)
{
cost = c;
}
void setId(unsigned int i)
{
id = i;
}
};
class ServerGameAction : public GameAction
{
ServerGameAction(){}
public:
void addPlayer(std::string p)
{
players.push_back(p);
}
std::string getLastPlayer() const
{
return players.back();
}
};
int main(int argc, char *argv[])
{
DBGameAction *dbga = 0;
ServerGameAction *sga = 0;
try {
dbga = new DBGameAction;
}
catch(...) /* Something happens wrong! */
{
return -1;
}
sga = reinterpret_cast<ServerGameAction*>(dbga);
sga->addPlayer("Max");
dbga->setCost(100);
std::cout << dbga->getCost() << std::endl;
std::cout << sga->getLastPlayer() << std::endl;
delete dbga;
sga = dbga = 0;
return 0;
}
答案 0 :(得分:0)
这是错误的程序设计。
您是否有理由不创建GameAction变量,然后将其转发到DBGameAction和ServerGameAction?
答案 1 :(得分:0)
我在很多场合都没有使用过reinterpret_cast,但我确信它不应该以这种方式使用。您应该尝试为类的接口找到更好的设计。使用你的课程的人,没有办法知道他需要做这种类型的演员来添加一个玩家。
你必须问自己,如果添加一个播放器是一个仅对ServerGameActions或DBGameActions有意义的操作。如果将播放器添加到DBGameActions是有意义的,那么AddPlayer也应该在DBGameAction的界面中。那你就不需要这些演员了。更进一步,如果它是一个对你可能拥有的每个可能的GameAction都有意义的操作,你可以把它放在基类的接口中。
答案 2 :(得分:0)
我过去曾经有效地使用过类似的模式,但它与大多数接口类设置略有不同。这提供了两个完全不同的功能集,而不是具有可以触发适当的特定于类的方法来完成不同数据类型上的类似任务的一致接口,它们各自具有自己的接口,但在相同的数据布局上工作。
我提出这种设计的唯一原因是基类只是数据并在多个库或可执行文件之间共享的情况。然后每个lib或exe定义一个子类,它包含允许在基础数据上使用的所有功能。例如,通过这种方式,您可以使用各种不错的额外函数构建服务器可执行文件,以处理客户端不允许使用的游戏数据,并且服务器端功能不会内置到客户端可执行文件中。游戏模型更容易触发现有的休眠功能,而不是编写和注入自己的功能。
关于直接在子类之间进行转换的问题的主要部分让我们担心。如果您发现自己想要这样做,请停下来并重新思考。理论上,只要您的类保持非虚拟并且派生类永远不会添加数据成员,您就可以摆脱演员表(由于对象切片,派生类无法为您尝试执行的操作提供任何数据) ,但这可能是危险的,而且很可能是代码不太可读。正如@dspfnder所讨论的那样,您可能希望使用基类来按需传递数据并按需转发以访问功能。
尽管如此,有很多方法可以隔离,限制或剔除功能。使用朋友类而不是子类的功能来重新设计您的设计可能是值得的。这将需要更少或不需要铸造。