【问题标题】:How to resolve "pure virtual method called"如何解决“调用纯虚方法”
【发布时间】:2012-05-29 06:06:06
【问题描述】:

我明白为什么会发生这种情况,但我一直在尝试解决它...这是我的代码在我的程序退出时生成错误(因此导致崩溃)时所做的事情...

pure virtual method called

SomeClass::~SomeClass()
{
   BaseClassObject->SomePureVirtualMethod(this);
}

void DerivedClass::SomePureVirtualMethod(SomeClass* obj)
{
    //Do stuff to remove obj from a collection
}

我从来没有打电话给new SomeClass,但我有一个QList<SomeClass*>,我将SomeClass*对象附加到它上面。 SomeClass 中的这个析构函数的目的是告诉DerivedClass 从它的QList<SomeClass*> 集合中删除SomeClass 的特定实例。

所以,举个具体的例子……

BaseClass = Shape

DerivedClass = Triangle

SomeClass = ShapeProperties 拥有对 Shape 的引用

所以,我从来没有打电话给new ShapeProperties,但我在Triangle 中有一个QList<ShapeProperties*>ShapeProperties 中的析构函数是告诉TriangleQList<ShapeProperties*> 的集合中删除ShapeProperties 的特定属性。

【问题讨论】:

    标签: c++ polymorphism derived-class base-class pure-virtual


    【解决方案1】:

    这可能发生的另一个原因取决于您的编译器和系统,那就是悬空引用。 Paul S. R. Chisholm explains释放内存的可能状态:

    • 内存可能被标记为已释放。
    • 内存可能被故意打乱。
    • 内存可能会被重复使用。
    • 记忆可能完全原样保留。

    最后一个是一个有趣的案例。对象是什么“完全一样 它是“?在这种情况下,它是抽象基类的一个实例; 当然,这就是 vtbl 留下的方式。如果我们尝试 为这样的对象调用纯虚成员函数?

    “调用的纯虚函数”。

    【讨论】:

      【解决方案2】:

      当您在基类SomeClass 的析构函数中调用virtual 方法时,它会调用基类SomeClass 的方法(SomePureVirtualMethod()),这是一个没有定义的纯虚方法。因此错误。

      为什么会这样?
      this 在构造函数或析构函数中的类型是其构造函数或析构函数被调用的类型,因此动态调度在构造函数和析构函数中不起作用,因为您希望它在所有其他函数中起作用。

      为什么会崩溃?
      因为从构造函数或析构函数调用纯虚函数是一种未定义行为

      C++03 10.4/6 状态

      “可以从抽象类的构造函数(或析构函数)调用成员函数;直接或间接对纯虚函数进行虚调用(10.3)的效​​果是从此类对象中创建(或销毁)的对象构造函数(或析构函数)未定义。”

      如何避免?
      只需确保不要从构造函数或析构函数调用纯虚函数即可。
      不要在构造函数或析构函数中调用virtual 方法,除非您了解所涉及的动态。

      【讨论】:

        【解决方案3】:

        当你的析构函数被调用时,继承类的析构函数已经被调用了。在构造函数和析构函数中,可以有效地将对象的动态类型视为与静态类型相同。也就是说,当您从构造函数/析构函数中调用虚方法时,调用的不是它们的覆盖版本。

        如果需要在析构函数中调用SomePureVirtualMethod,那么您必须在您想要的方法的实际定义所在的类的析构函数中调用它。

        【讨论】:

        • 那么如果我在派生构造函数中调用它,我怎么知道我指的是this的哪个实例?
        • 我可能误解了这一点,“如果 SomePureVirtualMethod 需要在析构函数中调用,那么你将不得不在你想要的方法的实际定义所在的类的析构函数中调用它。 "
        • @user869525:简单来说,您从析构函数调用SomePureVirtualMethod 不会解析为派生最多的覆盖。如果你想调用最派生的覆盖,你必须从实现这种覆盖的类的析构函数中调用它。
        • 是的,我明白这一点,但它不能解决我的问题,因为我在SomeClass,而不是BaseClass,也不是DerivedClass.SomeClass 拥有BaseClass 的实例并且DerivedClass 拥有listSomeClassSomeClass 中的析构函数需要从DerivedClass 内部的list 中删除SomeClass 的一个实例。
        猜你喜欢
        • 2011-01-11
        • 1970-01-01
        • 2012-07-01
        • 2018-02-10
        • 2019-04-19
        • 1970-01-01
        • 2012-06-14
        • 1970-01-01
        相关资源
        最近更新 更多