Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;临时-“;纯虚拟方法称为;_C++_Virtual Functions_Temporary_Pure Virtual - Fatal编程技术网

C++ c++;临时-“;纯虚拟方法称为;

C++ c++;临时-“;纯虚拟方法称为;,c++,virtual-functions,temporary,pure-virtual,C++,Virtual Functions,Temporary,Pure Virtual,据我所知,以下代码应该可以工作,但它不能 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; } 调用

据我所知,以下代码应该可以工作,但它不能

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()会产生一个“纯虚拟函数调用”错误。为什么会这样?我该怎么办?

您返回一个对临时变量的引用,当函数在
return
语句末尾结束时,该变量被破坏,并且您得到未定义的行为


您不能返回对临时对象的任何类型的引用,如果您按值返回
base
,您将得到切片,因此如果您真的希望这样做,您应该返回
std::unique\u ptr

我认为您不能返回对类似对象的引用。一旦foo()返回,派生()实例就会超出范围。有

base *foo() { return new derived(); }


应该可以工作。

您似乎希望
const
引用可以延长临时文件的生命周期。在某些情况下,这种情况不会发生。其中一种情况是返回临时文件时:

第二个上下文[在该上下文中,临时变量在与完整表达式结尾不同的点被销毁]是指引用绑定到临时变量。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生存期内持续存在,但以下情况除外:

[……]

  • 函数返回语句(6.6.3)中返回值的临时绑定的生存期没有延长;在return语句的完整表达式末尾销毁临时表达式
由于调用由
foo()
返回的对象的成员函数将需要从左值到右值的转换,并且该对象无效(不是从类型
base
派生的),因此会出现未定义的行为:

如果glvalue引用的对象不是
T
类型的对象,也不是从
T
派生的类型的对象,或者如果对象未初始化,则需要此转换的程序具有未定义的行为


调用期间没有对象,本地对象已被删除。没有vtable可看。尝试:

base& foo() { return *new derived(); }
临时“派生()”对象已在堆栈上分配。这可能与对象向上投射有关

const base&foo(){derived*d=new derived();return*d;}


对我来说效果很好。

将问题部分改为:

class A {
public:
  const base &foo() { return d; }
private:
  derived d;
};

这样,派生对象的生存期与A的生存期一样长,并且不会有任何问题。

确切地说,因为虚拟表也会被清理。。。这就是消息。@DougT:“未定义的行为”中没有“因为”。(除此之外,虚拟表永远不会被“清理”。)但是临时对象不应该在完整表达式的末尾销毁吗,也就是在virt()返回之后?@Dave不,为什么会?在
return
语句的末尾临时终止。@KerrekSB我不同意你的逻辑。“未定义的行为”不是“未察觉的行为”的承诺。如果C++编译器选择定义某些未定义的行为,它会不会停止为C++编译器?(也许你对这个问题有一个合理的答案。)也就是说,DougT关于vtable指针经历了对象破坏的推测似乎是合理的(即使他的术语是错的)。他不应该依赖于UB中注意到的模式,但你似乎在说他也被禁止注意到它们。当然,如果你想使用shared_ptr或类似的东西,在真正的代码中你应该这样做。然而,我的观点基本上是,我们需要分配堆上的对象才能工作,为什么要把这一事实隐藏在指针恐惧的外衣下?@Johannes:因为这只是要求内存泄漏。智能指针在标准库中–使用它们!:-]@因为我们正在教育同龄人解决问题的技巧和良好习惯
unique\u ptr
在很多情况下甚至没有运行时惩罚。调用方如何知道他必须释放内存?如果我在函数
bar
的堆栈上构造了一个,并从
bar
返回了对
d
的引用,会怎么样?当然-谢谢你的关注。我本可以使用boost::shared\u ptr
class A {
public:
  const base &foo() { return d; }
private:
  derived d;
};