2013-05-08 163 views
0

我必须编写一个程序,它的一个函数将通过抽象基类返回派生类,所以当返回到主类的类可以访问派生类虚拟方法。通过其抽象基类的指针返回派生类对象

请记住,我不能在主程序中更改任何内容,因为我不是写它的人。

#include<iostream> 
using namespace std; 
class A 
{ 
private: 
public: 
    virtual void DoIt(void)=0; 
    A(void){}; 
    ~A(void){}; 
}; 
class B: 
     public A 
{ 
private: 
    int Num; 
public: 
    virtual void DoIt(void){Num=7;cout<<"its done";}; 
    B(void){}; 
    ~B(void){}; 
}; 
A& returnValue(void) 
{ 
     B item; 
    return item; 
} 
void main() 
{ 
    A& item=returnValue(); 
    item.DoIt(); 
} 

当我尝试运行这个最后的换行符构建说DoIt是一个纯虚函数调用。 有什么想法?

+1

是否修复了'returnValue'的签名?你不应该返回一个局部变量的引用。 – 2013-05-08 19:43:05

+0

它不是固定的。我可以决定如何重振我的价值。 – petric 2013-05-08 19:44:54

+1

这是问题所在。动态分配'item'('B * item = new B;')。然后返回一个指针或对它的引用。这应该解决它。 – stardust 2013-05-08 19:48:08

回答

1

您正在返回对returnvalue中的调用完成时销毁的局部变量的引用。相反,请尝试以下操作:

A &returnValue(void) { 
    return *(new B); 
} 

int main() { 
    A& item = returnValue(); 
    item.DoIt(); 
} 

更好的解决方案是返回一个智能指针,让人们保持主要功能采取了对象的生命周期由returnvalue返回责任:

#include <memory> 
... 
std::unique_ptr<A> returnValue(void) { 
    return std::unique_ptr<A>(new B); 
} 

int main() { 
    auto item = returnValue(); 
    item->DoIt(); 
} 
1

item当函数退出时,您返回的returnValue()被破坏。这个函数返回的是对被销毁对象的引用。你需要以某种方式保存对象。例如:

A& returnValue(void) 
{ 
    B *item = new B(); 
    return *item; 
} 
void main() 
{ 
    A& item=returnValue(); 
    item.DoIt(); 
    delete &item; // A's destructor must be virtual for this to work correctly 
} 

或:

B theItem; 
A& returnValue(void) 
{ 
    return theItem; 
} 
void main() 
{ 
    A& item=returnValue(); 
    item.DoIt(); 
} 

BTW您收到“纯虚函数调用”错误的机会:到时候你拨打item.DoIt()虚表指针被修改(由B的析构函数)指向A的虚拟成员,并将纯虚函数存储到显示此错误的函数中。但是不能保证达到它,因为虚拟表指针已经驻留在释放的堆栈内存中。编译器可能已经完全重用了这个内存。

0

这里有几个问题。主要的原因是itemreturnValue立即超出范围,因此不再有主体上的对象DoIt。因此,没有哪个对象遵循继承树。这解释了您得到的错误(item in main不再是B类型,因为它不存在)。然而,我很惊讶它不会崩溃。

要解决此问题,您需要为对象创建副本(按值传递而不是引用)或在堆上创建对象(并传递指针)。对于后者:

A* returnValue(void) 
{ 
     B* item = new B; 
    return item; 
} 

int main() 
{ 
    A* item=returnValue(); 
    item->DoIt(); 
    delete item; 
} 

的另一个问题是,你有虚函数,而不是虚析构函数! This can be a serious issue.你会想要virtual ~A(void){};virtual ~B(void){};是安全的。

+0

谢谢大家对于我真正感激的答案,但请告诉我,如果我将在函数中动态分配它,我将如何确保它被删除? – petric 2013-05-08 19:59:25

+0

通过在完成它时调用删除。大概在你称之为“returnValue”的函数结束时(这里是main的结尾)。 – Corey 2013-05-08 20:04:32

+0

正如我所说,我没有控制主 – petric 2013-05-08 20:06:50