据我了解临时代码,以下代码应该有效,但事实并非如此。
struct base
{
virtual~base() {}
virtual void virt()const=0;
};
struct derived:public base
{
virtual void virt()const {}
};
const base& foo() {return derived();}
int main()
{
foo().virt();
return 0;
}
对virt()的调用给出了一个“纯虚函数调用”错误。为什么这样,我该怎么办?
答案 0 :(得分:8)
当return
语句结束时函数结束并且你得到未定义的行为时,你正在返回对一个被破坏的的临时引用。
您不能将任何类型的引用返回给临时文件,如果按值返回base
,您将获得切片,因此如果您真的希望这样做,则应返回{{1} }。
答案 1 :(得分:5)
您似乎期望const
引用延长临时的生命周期。在某些情况下,这种情况不会发生。其中一种情况是返回一个临时的:
第二个上下文[其中temporaries在与完整表达式的结尾不同的点被销毁]是指引用绑定到临时的。引用绑定的临时值或作为绑定引用的子对象的完整对象的临时值在引用的生命周期内持续存在,除了:
[...]
- 不扩展函数返回语句(6.6.3)中返回值的临时绑定的生存期;临时在return语句中的full-expression结束时被销毁。
由于调用foo()
返回的对象的成员函数将需要进行左值到右值的转换并且对象无效(不是从类型base
派生的),因此会得到未定义的行为:< / p>
如果glvalue引用的对象不是
T
类型的对象,并且不是从T
派生的类型的对象,或者如果对象未初始化,则需要这样的程序转换有未定义的行为。
答案 2 :(得分:3)
我认为你不能返回对这类对象的引用。一旦foo()返回,derived()实例就会超出范围。有
base *foo() { return new derived(); }
和
foo()->virt();
应该有用。
答案 3 :(得分:0)
调用期间没有对象,删除了本地对象。没有vtable可以看。试试:
base& foo() { return *new derived(); }
答案 4 :(得分:0)
您的临时'derived()'对象在堆栈上分配。它可能与对象上传有关。
const base&amp; foo(){derived * d = new derived(); return * d; }
对我来说工作得很好。
答案 5 :(得分:0)
将问题片段更改为:
class A {
public:
const base &foo() { return d; }
private:
derived d;
};
这样,派生对象的生命周期与A的生命周期一样长,并且永远不会有任何问题。