当我从基础构造函数调用虚函数时,编译器不会给出任何错误。但是当我从基类构造函数调用纯虚函数时,它会产生编译错误。
考虑下面的示例程序:
#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()'调用 来自构造函数
这是什么原因?
答案 0 :(得分:10)
不要从构造函数调用纯虚函数,因为它会导致未定义的行为。
C ++ 03 10.4 / 6州
&#34;可以从抽象类的构造函数(或析构函数)调用成员函数;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用(10.3)的效果是未定义的。&#34;
您收到编译错误,因为您尚未在Base类中定义纯虚函数virtualfunc()
。为了能够召唤它,它必须有一个身体。
无论如何,应该避免在构造函数中调用纯虚函数,因为这样做是未定义的行为。
答案 1 :(得分:2)
在C ++ 11中,有一个解决方法。
在构造函数委派过程中,您实际上可以调用纯虚方法的实现 - 只要在纯虚拟虚拟方法之前完成实现该纯虚方法的类的至少一个构造函数调用了调用。
你可以/应该使用&#34; final&#34;关键字,以确保子类的行为不可预测。
请参阅:C++ 11 Delegated Constructor Pure Virtual Method & Function Calls — Dangers?
#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;
}
答案 2 :(得分:1)
您应该记住,当您在基类构造函数中时,没有派生类。更多信息:
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5
当您尝试调用纯虚函数时,尚未执行它。
有很多解决方案。最简单的方法是创建另一个成员函数 “init()”,您将在基类的构造函数之后调用它。