我想制作一个多线程模型,其中服务器主循环不会被挂起的数据库事务停止。所以我做了一些简单的类,这是一个非常简化的版本:
enum Type
{
QueryType_FindUser = 1 << 0,
QueryType_RegisterUser = 1 << 1,
QueryType_UpdateUser = 1 << 2,
//lots lots and lots of more types
};
class Base
{
public:
Type type;
};
class User: public Base
{
public:
std::string username;
User(std::string username)
:username(username)
{type = QueryType_FindUser;}
};
现在,当我将数据作为Base
传输时,我想再次将其转换回User
类:
concurrency::concurrent_queue<QueryInformation::Base> BackgroundQueryQueue;
void BackgroundQueryWorker::Worker()
{
while(ServerRunning)
{
QueryInformation::Base Temp;
if(BackgroundQueryQueue.try_pop(Temp))
{
switch(Temp.type)
{
case QueryInformation::Type::QueryType_FindUser:
{
QueryInformation::User ToFind(static_cast<QueryInformation::User>(Temp));//error here
//do sql query with user information
break;
}
//etc
}
}
boost::this_thread::sleep(boost::posix_time::milliseconds(SleepTime));
}
}
在我标记//errorhere
行时,它表示没有用户定义的从Base
到User
的转换,我该怎么办?如何定义此转换?
我是多态的新手,所以另外解释为什么这不编译也会很棒:) 根据我对多态性的理解,它应该可以在base&lt; - &gt;派生之间自由转换..
答案 0 :(得分:4)
您只能使用指针或引用来使用多态,而不能使用直接值。
因此,你应该使用:
QueryInformation::User * user = static_cast<QueryInformation::User *>(&Temp);
并相应地修改代码以使用指针而不是直接值。
此外,您分配Temp
的方式确实属于班级Base
,而不是班级User
,因此其“类型”不会是QueryType_FindUser
,然后static_cast
将不会执行(您不会输入case
值。)
static_cast
的多态性的正常使用应如下所示:
QueryInformation::Base * temp = new QueryInformation::User;
// or obtain by some other methods, so that you don't know the exact
// type, but anyway you *must* use a pointer (or reference).
switch(temp->type)
{
case QueryInformation::Type::QueryType_FindUser:
{
QueryInformation::User * user = static_cast<QueryInformation::User*>(temp);
}
}
在您的情况下,这意味着而不是:
concurrency::concurrent_queue<QueryInformation::Base> BackgroundQueryQueue;
你应该(注意指针):
concurrency::concurrent_queue<QueryInformation::Base *> BackgroundQueryQueue;
正如Mats建议的那样,调用Base
的虚拟方法可以更好地自动执行调度,而不是自己创建switch
并手动设置static_cast
答案 1 :(得分:1)
对我而言,这似乎有点不对劲。
首先,您的数据结构concurrent_queue<QueryInformation::Base>
正在存储Base
对象,这意味着实际对象中的任何其他信息(例如User
)将因切片而丢失。您需要使用(智能)指针来存储Base
对象的地址 - 然后它将能够容纳任何大小的对象。
第二,当然,这应该使用虚函数来实现所需的任务。如果你存储它是什么类型的对象,然后调用dynamic_cast
来转换对象,那就是“错误”。当然,有一些罕见的情况,这是正确的事情,但大多数时候,dynamic_cast
(或static_cast
)在一个对象之间转换是一个“难闻的气味”,并且你可能知道,应该避免难闻的气味。