C++经验(四)-- 基类构造函数和析构函数中调用virtual虚函数?

class Base
{
public:
    Base();
    virtual void oneFunction() = 0;
    ...
};

Base::Base()
{
    ...
    oneFunction();
}

class Derived : public Base
{
public:
    Derived(){};
    virtual void oneFunction()
	{
		std::cout << "Derived oneFunction...";
	}
}

当我们调用下面的代码时会出现什么情况了?

Derived d;

首先,编译器发出了一个警告,纯虚函数在构造函数中被调用。

[Warning] pure virtual 'virtual void Base::oneFunction()' called from constructor

接着,因为上面我们的函数oneFunction是纯虚函数,因此编译器会报错,undefined。

cppt.cpp:(.text+0x1f): undefined reference to `Base::oneFunction()'

然后,程序结束运行。

[Error] ld returned 1 exit status

我们试着理解一下上面的整个过程。

  • 首先会调用Base的构造函数,并且在构造函数里面调用了oneFunction方法;
  • 调用Derived的构造函数

在调用Base构造函数的时候,末尾调用了一个virtual类型的函数,但是此时,Derived的对象 d 中属于Derived的部分并没有被创建出来,也就是Derived的构造函数还没有调用,那么,调用的oneFunction方法就是属于Base的部分。

也就是说,在base class被构建的时候,virtual函数是不会下降到derived class 中的。更直接一点,在base class被构建的时候,virtual函数不是virtual函数。

同样的道理在析构函数的时候也是一样的,当derived函数的析构函数运行之后,derived class部分的变量等都已被析构,此时,当析构运行到base class的析构函数时,如果尝试调用了derived class的虚函数实现部分,则会出现不可预知的错误。

我们尝试将上面的纯虚函数修改为虚函数试试。

class Base
{
public:
	virtual void oneFunction()
	{
		std::cout << "Base oneFunction...";
	}
    Base()
    {
       oneFunction(); 
   }
};

class Derived : public Base
{
public:
	Derived(){	};
	virtual void oneFunction()
	{
		std::cout << "Derived oneFunction...";
	}
};

修改后,在调用的时候,就会发现虽然程序能够正常运行,但是调用的版本是base class部分的虚函数。而这也不是我们所希望的版本。

所以,如果我们想要在 每一个 derived class 继承 base class的时候,都能调用适当版本的oneFunction,那么,在构造函数中调用虚函数或者纯虚函数是不能实现的。

解决方法是将虚函数属性去掉,调用一个 non-virtual的函数。

#include
#include

class Base
{
public:
	Base(const std::string& param);
	void oneFunction(const std::string& param) const 
	{
		std::cout << param;
	}
};

Base::Base(const std::string& param)
{
	oneFunction(param);
}

class Derived : public Base
{
public:
	Derived(const std::string& param) : Base(createOneFunction(param))
	{
		
	}
private:
	static std::string createOneFunction(const std::string& param);
};

std::string Derived::createOneFunction(const std::string& param)
{
	return param + " Derived...";	
}

int main()
{
	Derived d("test");
	return 0;
} 

上面的例子中我们定义了一个非虚函数,并在base class的构造函数中调用,然后在derived class对象被创建的时候传入需要的参数。也就是借由derived class将必要的构造信息上传致base class构造函数来代替向下调用的虚函数

在构造函数或者析构函数中调用virtual虚函数并不会满足我们需求。因为这类调用不会下降到派生类中。

你可能感兴趣的:(C/C++,c++,开发语言,构造函数调用虚函数,析构函数调用虚函数)