5

当我从基本构造函数调用虚函数时,编译器不会给出任何错误。但是当我从基类构造函数调用纯虚拟函数时,它会产生编译错误。

考虑下面的示例程序:

#include <iostream>

using namespace std;
class base
{
   public:
      void virtual virtualfunc() = 0;
      //void virtual virtualfunc();
      base()
      {
         virtualfunc();
      }
};

void base::virtualfunc()
{
   cout << " pvf in base class\n";
}

class derived : public base
{
   public:
   void virtualfunc()
   {
      cout << "vf in derived class\n";
   }
};

int main()
{
   derived d;
   base *bptr = &d;
   bptr->virtualfunc();

   return 0;
}

这里可以看出纯虚函数是有定义的。我希望在bptr->virtualfunc()执行时调用基类中定义的纯虚函数。相反,它给出了编译错误:

错误:从构造函数调用抽象虚拟`virtual void base::virtualfunc()'

这是什么原因?

4

4 回答 4

10

不要从构造函数调用纯虚函数,因为它会导致Undefined Behavior

C++03 10.4/6 状态

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

你得到一个编译错误,因为你没有virtualfunc()在 Base 类中定义纯虚函数。为了能够调用它,它必须有一个身体。

无论如何,应该避免在构造函数中调用纯虚函数,因为这样做是未定义的行为。

于 2011-12-27T08:02:12.833 回答
2

在 C++ 11 中,有一个变通方法。

在构造函数委托的过程中,实际上可以调用一个纯虚方法的实现——只要在调用纯虚调用之前,实现该纯虚方法的类的构造函数中至少有一个已经完成.

您可以/应该使用“final”关键字以确保子类的行为不可预测。

请参阅:C++ 11 委托构造函数纯虚方法和函数调用——危险?

#include <string>

/**************************************/
class Base
{
public:
    int sum;
    virtual int Do() = 0;

    void Initialize()
    {
        Do();
    }
    Base()
    {
    }
};

/**************************************/
// Optionally declare class as "final" to avoid
// issues with further sub-derivations.
class Derived final : public Base
{
public:

    virtual int Do() override final
    {
        sum = 0 ? 1 : sum;
        return sum / 2 ; // .5 if not already set.
    }

    Derived(const std::string & test)
        : Derived() // Ensure "this" object is constructed.
    {
        Initialize(); // Call Pure Virtual Method.
    }
    Derived()
        : Base()
    {
        // Effectively Instantiating the Base Class.
        // Then Instantiating This.
        // The the target constructor completes.
    }
};




/********************************************************************/
int main(int args, char* argv[])
{
    Derived d;
    return 0;
}
于 2013-02-04T19:01:03.477 回答
1

您应该记住,当您在基类构造函数中时,没有派生类。更多信息:</p>

http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5

当您尝试调用纯虚函数时,还没有实现它。

有很多解决方案。最简单的方法是创建另一个成员函数“init()”,您将在基类的构造函数之后调用它。

于 2011-12-27T08:29:16.177 回答
0

编译器不需要假定在构造函数完成之前已经为纯虚函数设置了指针。换句话说,不需要知道此时您有该函数的定义。因此行为是未定义的。在某些编译器 (MSVC) 上,它会按您的预期工作,而在其他编译器上,它会给您当前遇到的错误。在其他一些上它会编译,但你会得到一个分段错误。

无论如何,从构造函数调用任何虚函数确实是一个坏主意,因为它会使代码的意图变得模糊和混乱。

于 2011-12-27T08:38:45.857 回答