多态中的纯虚函数
使用多态时,当子类继承父类之后,一般来说对于父类只是作为提供相应的成员变量和成员函数的一个集合。
在实际项目中,如果想要修改某一部分的功能,按照以往普通的类的写法,就需要修改类中的代码,也可以说是源码,这样会显得很不方便和不安全,因此,我们只希望父类作为一个提供成员变量和成员函数的一个集合(接口?)在父类外进行实现,而父类的成员函数一般只做声明,不做实现,这也是使用多态的一个目的。
对于纯虚函数,当父类中的函数只做一个声明时,为了简化写法,就可以直接写为纯虚函数。
//纯虚函数的写法:virtual 函数返回类型 函数名() = 0
#include
using namespace std;
class base
{
public:
//这里创建了一个纯虚函数func()
virtual void func() = 0;
public:
};
当类中有任何一个函数变为了纯虚函数之后,该类就会变成一个抽象类
- 抽象类的特点:
- 无法实例化对象
- 抽象类的子类 必须要重写父类中的纯虚函数 否则也属于抽象类(重写的语法,之前已做过笔记)
完整代码:
#include
using namespace std;
//纯虚函数和抽象类
class base
{
public:
//纯虚函数的写法:
virtual void func() = 0;
//只要有一个纯虚函数,这个类就成为抽象类
//纯虚函数的特点:
//1、无法实例化对象
//2、抽象类的子类 必须要重写父类中的纯虚函数 否则也属于抽象类
public:
};
class son :public base
{
public:
void func()
{
cout << "子类函数的调用" << endl;
}
};
void test02()
{
son s;//子类必须要重写父类中的俄纯虚函数,否则不能实例化对象
//多态函数调用的条件 父类指针需要指向子类
base* b = new son;
b->func();
delete b;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
虚析构函数
根据c++的只是可以知道,析构函数一般用于,该对象所在的函数运行完最后一行代码之后,对类中内存进行释放。
一般来说析构函数在写类的时候,不需要我们写,编译器(visual studio)内部会自动生成并调用。
- 在多态语法中,使用虚析构函数和纯虚析构函数的一般条件是:
子类中存在堆区数据
在一般情况下,在使用多态语法之后,如果不使用虚析构语法,若子类中含有堆区上的数据,函数运行完成之后,只会运行父类的析构函数,而不会运行子类的析构函数(尽管子类中实现了析构函数),从而会造成内存泄漏的状况
#include
using namespace std;
class animal
{
public:
animal()
{
cout << "animal的构造函数的调用" << endl;
}
virtual void speak() = 0;
//这里在父类中实现了析构函数
~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()
{
if (m_name != NULL)
{
cout << "cat析构函数的调用" << endl;
delete m_name;
m_name = NULL;
}
}
public:
string *m_name;
};
void dospeak(animal * an)
{
//父类指针再调用析构函数的时候,不会调用子类种的是析构函数,导致子类如果有堆区属性,会出现内存泄露的情况
an->speak();
delete an;
}
void test01()
{
dospeak(new cat("tom"));
}
int main()
{
test01();
system("pause");
return 0;
}
animal的构造函数的调用
cat构造函数的调用
tom小猫说话
animal的析构 函数的调用
可以看出并没有调用子类的析构函数。
如果想要避免内存泄露的情况,就需要在父类的析构函数前加上virtual关键字
class animal
{
public:
animal()
{
cout << "animal的构造函数的调用" << endl;
}
virtual void speak() = 0;
virtual ~animal()
{
cout << "animal的析构 函数的调用" << endl;
}
};
输出结果:
animal的构造函数的调用
cat构造函数的调用
tom小猫说话
cat析构函数的调用
animal的析构 函数的调用
可以看出调用了子类cat的析构函数
纯虚析构函数
纯虚析构函数就是在虚析构函数的基础上,用纯虚函数的写法去写虚析构函数
class animal
{
public:
animal()
{
cout << "animal的构造函数的调用" << endl;
}
virtual void speak() = 0;
//如果是纯虚析构函数的俄写法,则需要在类内声明之后,还需要在类外实现
//有了纯虚析构之后,这个类也属于抽象类,不可实例化
virtual ~animal() = 0;
};
#纯虚析构函数需要在类外进行实现
animal::~animal()
{
cout << "纯虚析构函数的的实现" << endl;
}
输出结果:
animal的构造函数的调用
cat构造函数的调用
tom小猫说话
cat析构函数的调用
animal的析构 函数的调用
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)