哪些函数不可以成为虚函数?构造函数和析构函数可以是虚函数吗?
程序员文章站
2022-03-15 16:33:25
...
哪些函数不能成为虚函数?
- 普通函数:普通函数不属于成员函数,是不能被继承的。普通函数只能被重载,不能被重写,因此声明为虚函数没有意义。因为编译器会在编译时绑定函数。
- 构造函数:只有当调用了构造函数,这个对象才能产生,如果把构造函数写成虚函数,这时候我们的对象就没有办法生成。更别说用对象去调用了。所以构造函数不能成为虚函数。
- 静态成员函数:静态成员函数是属于类的,不依赖于对象调用,所以也不能成为虚函数。
- 友元函数:友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。
- 内联函数:内联函数在编译时就被展开,它不能产生函数符号,所以不能往虚表中存放,自然就不能成为虚函数。
析构函数作为虚函数---虚析构
当子类有在堆上申请空间的操作,那么父类指针在释放时无法调用到子类的析构函数,这时就会造成内存泄漏。
解决方式:将父类中的析构函数改为虚析构或者纯虚析构。
虚析构和纯虚析构都可以解决父类指针释放子类对象,都需要有具体的函数实现。
语法:
- 虚析构:
virtual ~类名(){}
- 纯虚析构:
virtual ~类名() = 0;
类名::~类名(){}
下面一个例子:
#include<iostream>
using namespace std;
class Animal {
public:
Animal(){
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
/*//析构函数加上virtual关键字,变成虚析构函数
virtual ~Animal(){
cout << "Animal虚析构函数调用!" << endl;
}*/
virtual ~Animal() = 0; //纯虚析构函数
};
Animal::~Animal(){
cout << "Animal 纯虚析构函数调用!" << endl;
}
//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
class Cat : public Animal {
public:
Cat(string name){
cout << "Cat构造函数调用!" << endl;
m_Name = new string(name);
}
virtual void Speak(){
cout << *m_Name << "小猫在说话!" << endl;
}
~Cat(){
cout << "Cat析构函数调用!" << endl;
if (this->m_Name != NULL) {
delete m_Name;
m_Name = NULL;
}
}
public:
string *m_Name;
};
int main() {
Animal *animal = new Cat("Tom");
animal->Speak();
delete animal;
return 0;
}
总结:
- 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
- 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
- 拥有纯虚析构函数的类也属于抽象类