通过抽象基类的指针返回派生类对象
returning a derived class object through a pointer of its abstract base class
我必须编写一个程序,其中一个函数将通过抽象基类返回派生类,因此当类返回到主程序时可以访问派生类的虚方法。
请记住,我不能更改主程序中的任何内容,因为我不是编写主程序的人。
#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
是一个纯虚函数调用。什么好主意吗?
您正在返回对局部变量的引用,该引用在returnvalue
中的调用完成时被销毁。不如试试下面的命令:
A &returnValue(void) {
return *(new B);
}
int main() {
A& item = returnValue();
item.DoIt();
}
一个更好的解决方案是返回一个智能指针,让维护main函数的人对returnvalue
返回的对象的生命周期负责:
#include <memory>
...
std::unique_ptr<A> returnValue(void) {
return std::unique_ptr<A>(new B);
}
int main() {
auto item = returnValue();
item->DoIt();
}
在returnValue()
中返回的item
在函数退出时被销毁。这个函数返回的是对销毁对象的引用。你需要以某种方式保存对象。例如:
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
的虚成员,而纯虚函数被存根为一个显示此错误的函数。但是,不能保证能够到达它,因为虚拟表指针已经驻留在释放的堆栈内存中。编译器可能已经将这些内存完全重用到其他地方了。
这里有几个问题。主要原因是returnValue
中的item
将立即超出作用域,因此在main中不再有可以调用DoIt
的对象。因此,没有对象可以跟随继承树。这解释了您得到的错误(main中的item
不再是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){};
都是安全的。
相关文章:
- 返回派生类型时出现协变类型错误
- C++ 基类调用但返回派生类
- typeid.name 返回派生类类型之前的数字
- 无法返回派生类型的标准::unique_ptr<>
- 如何在不转换回基类类型的情况下返回派生类型的对象?
- 从虚拟方法返回派生对象作为基础
- 不能返回派生的类(无法转换)
- 使用动态铸件来返回派生类内部的变量的不同值
- 如何返回派生类型
- 继承的函数返回派生类,而不是基类
- 从基类成员函数返回派生类的实例
- 如何重写 QObject::findChildren 以仅返回派生类型
- 从基类型的函数返回派生类对象
- 基类方法返回派生类 objec
- 重写虚拟方法时无法返回派生类指针
- 具有基类向量的类的下标运算符重载,该向量必须返回派生类
- 从指向基类型的指针向量,返回派生类型的第一个元素,该元素被强制转换为派生类型
- 返回派生类类型的基类中的方法
- 在基类和派生类上操作时如何返回派生类型
- 通过抽象基类的指针返回派生类对象