我正在尝试实现多态队列。 这是我的试用版:
QQueue <Request *> requests;
while(...)
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
if(...)){
Request *request=new Request();
request->tcpMessage=line.toUtf8();
request->decodeFromTcpMessage(); //this initialize variables in request using tcpMessage
if(request->requestType==REQUEST_LOGIN){
LoginRequest loginRequest;
request=&loginRequest;
request->tcpMessage=line.toUtf8();
request->decodeFromTcpMessage();
requests.enqueue(request);
}
//Here pointers in "requests" do not point to objects I created above, and I noticed that their destructors are also called.
LoginRequest *loginRequest2=dynamic_cast<LoginRequest *>(requests.dequeue());
loginRequest2->decodeFromTcpMessage();
}
}
不幸的是,由于我在第二条评论中提到的原因,我无法使用此代码设置工作多态队列。我猜,我需要使用智能指针,但是如何? 我愿意改进我的代码或多态队列的新实现。
感谢。
答案 0 :(得分:2)
您将无效指针指向QQueue
。如果QQueue
保存指针,则需要创建在堆上插入的每个对象,即调用new
。此外,如果您不需要,请不要忘记释放第一个创建的Request
。
我认为您应该将代码重写为:
...
if(request->requestType==REQUEST_LOGIN){
delete request;
request = new LoginRequest();
request->tcpMessage=line.toUtf8();
...
}
使用此代码,您之后的dynamic_cast<LoginRequest*>
不会失败。
答案 1 :(得分:2)
您的来源有两个问题:
Request *request=new Request();
声明了内存,后者被request=&loginRequest;
分配放弃(并且不再可删除)LoginRequest loginRequest;
变量被破坏,导致
request
中的悬空指针我建议删除Request *request=new Request();
行,稍后在if(...){
块中指定具体的LoginRequest
对象
LoginRequest* loginRequest = new LoginRequest(); /* fill the request */ requests.enqueue(loginRequest);
您可以通过在排队队列(从处理完毕后)或在队列中使用容器安全智能指针时手动删除它们来删除排队对象。 :: shared_ptr很好,也许QT也有其中一个, std :: auto_ptr不是容器安全的)。
PITFALL 还要确保Request的析构函数是虚拟的,因为当基类中没有虚拟析构函数时,你不能通过指向其基本classe的指针删除对象(c ++可以调用基类)在这种情况下使用派生类实例的类析构函数,导致未定义的行为,如内存泄漏或崩溃)
答案 2 :(得分:1)
立即从代码片段中我可以看到Request的对象排队,稍后您尝试将其向下转发到LoginRequest。 dynamic_cast肯定会失败。您必须解析请求数据并创建从Request派生的适当类的对象。我建议使用Factory Pattern。
答案 3 :(得分:1)
这也是使用工厂的好地方,IMO。
if(...)){
Request *request = CreateRequest(message);
requests.enqueue(request);
}
Request* request = requests.pop();
LoginRequest* login_req = dynamic_cast<LoginRequest*>(request);
if (login_req != NULL)
whatever;
,其中
Request* CreateRequest(TcpMessage* message)
{
TcpMessage* message = line.toUtf8();
RequestType type = message->GetRequestType();
Request* req = NULL;
switch (type)
{
case REQUEST_LOGIN:
req = new LoginRequest(message);
break;
etc.
}
delete message;
return req;
}
...然后,您的构造函数自然会对消息做正确的事情,正确初始化对象。