赞
踩
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.不要在构造函数和析构函数中调用虚函数。
因为在构造函数中,对象还不完整,所以虚表指针可能还没初始化好,那么调用虚函数,就会发生未定义行为;
因为在析构函数中,会将对象某些成员清理,那么对象也不完整,同理,会发生未定义行为。
---------------------
作者:sophia__yu
来源:CSDN
原文:https://blog.csdn.net/sophia__yu/article/details/82796841
版权声明:本文为博主原创文章,转载请附上博文链接!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。