静态成员函数、内联函数、构造函数、析构函数、operator=是否可以定义为虚函数?

1.静态成员函数:静态成员函数属于类,也属于对象,但最终属于类,在内存中只有一份,即没有this指针;而虚函数必须根据指向哪一个对象来确定调用谁的虚函数,即虚函数要在有对象的基础上才可以。所以静态成员函数不可以定义为虚函数。
2.内联函数:由于内联函数是直接展开代码,并不存在函数调用,即没有函数地址,那么就不能存在虚表中,所以内联函数不可定义为虚函数
3.构造函数:虚表指针是存储在对象的内存空间,当调虚函数时,是通过虚表指针指向的虚表里的函数地址进行调用的。如果将构造函数定义为虚函数,就要通过虚表指针指向的虚表的构造函数地址来调用。而构造函数是实例化对象,定义为虚函数后,对象空间还没有实例化,那就没有虚表指针,自然无法调用构造函数,那构造函数就失去意义,所以不能将构造函数定义为虚函数。
4.析构函数:最好将基类的析构函数定义为虚函数

class Person
{
public:
	~Person()
	 {
		cout << "~Person()" << endl;
	}
protected:
	string _name;
};
class Student: public Person
{
public:
	~Student()
	{
		free(_num);
		cout << "	~Student()" << endl;
	}
protected:
	string  _num;
};
int main()
{
	Person *p = new Student(); // 开Student类的空间,call子类构造函数,基类指向这段空间
	delete p;  //先析构,再free
	system("pause");
	return 0;
}

在这里插入图片描述
因为delete p :调析构函数是普通函数调用,普通函数调用和对象类型有关,p的对象类型是Person,那就会调基类的析构函数,即没有调子类的析构函数。那么子类的_num就会没有free,从而造成内存泄漏。
如果将基类析构函数定义为虚函数:

virtual ~Person()
	{
		cout << "~Person()" << endl;
	}
	 ~Student()  //子类可以不加virtual ,也可以构成多态
	{
		cout << "~Student()" << endl;
	}
	//析构函数的重写是特例,基类和派生类析构函数在编译阶段被处理成相同函数名(destructor)

在这里插入图片描述
因为Person *p = new Student();而p指向子类Student 的对象,析构是虚函数,就会掉Student的析构函数,而子类的析构函数又自动调了父类的析构函数,这样就不会造成资源泄漏等问题。
5.operator=:虽然可以把operator=定义为虚函数(返回值不同,可以构成协变),但最好不要将operator=定义为虚函数,因为使用时容易引起混淆且没有意义。
6.不要在构造函数和析构函数中调用虚函数。
因为在构造函数中,对象还不完整,所以虚表指针可能还没初始化好,那么调用虚函数,就会发生未定义行为;
因为在析构函数中,会将对象某些成员清理,那么对象也不完整,同理,会发生未定义行为。

猜你喜欢

转载自blog.csdn.net/sophia__yu/article/details/82796841
今日推荐