通过其抽象基类的指针返回派生类对象

时间:2013-05-08 19:39:59

标签: c++ class pointers virtual

我必须编写一个程序,它的一个函数将通过一个抽象基类返回一个派生类,所以当返回给main的类可以访问派生类的虚方法时。

请记住,我不能改变主程序中的任何内容,因为我不是那个人写的。

#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是纯虚函数调用。 任何想法?

3 个答案:

答案 0 :(得分: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 :(得分: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();
}

顺便说一下,您偶然收到“纯虚函数调用”错误:当您调用item.DoIt()时,虚拟表指针被修改(由B的析构函数)指向{{1} }的虚拟成员,纯虚函数被存根到显示此错误的函数。但是,您无法保证到达它,因为虚拟表指针已驻留在释放的堆栈内存中。编译器可能已经完全重用了这个内存。

答案 2 :(得分:0)

这里有几个问题。主要的一点是item中的returnValue会立即超出范围,因此main中不再有一个对象可以调用DoIt。因此,没有对象可以跟随继承树。这解释了你得到的错误(main中的item不再是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){};都安全。