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

4

3 回答 3

1

您正在返回对 in 调用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();
}
于 2013-05-08T19:51:36.137 回答
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的析构函数)修改为指向A的虚拟成员,并且纯虚函数被存根到显示此内容的函数错误。但是,您不能保证可以访问它,因为虚拟表指针已经驻留在释放的堆栈内存中。编译器可能已经完全重用了这个内存来做其他事情。

于 2013-05-08T19:51:36.410 回答
0

这里有几个问题。主要的是iteminreturnValue立即超出范围,因此 main 中不再有可以调用的对象DoIt。因此,没有对象可以跟随继承树。这解释了您得到的错误(item在 main 中不再属于 B 类型,因为它不存在)。然而,我很惊讶它不仅仅是崩溃。

要解决此问题,您将需要制作对象的副本(通过值而不是引用传递)或在堆上制作对象(并传递指针)。对于后者:

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

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

另一个问题是你有虚函数,但没有虚析构函数!这可能是一个严重的问题。你会想要两者virtual ~A(void){};并且virtual ~B(void){};是安全的。

于 2013-05-08T19:53:42.117 回答