本人对java可能比较熟悉,现在在学习C++的过程,会与Java进行对比的学习,在学习到多态的时候,对虚函数,纯虚函数和普通函数的概念不是很清楚,在查阅资料后,进行一个梳理
首先是Java中,比如类A继承自类B,类B中的方法只要不是Final修饰的,类A都可以对其进行重写,而且在调用的时候,对执行类A中重写后的方法。而C++就有所不同了。
在C++中,比如类A继承自类B,类B中的方法如果没有用virtual修饰的,那么这个方法就是普通方法,类A就不应该对其进行重写,因为即使重写后,类A中调用该方法执行的还是类B的方法。类似于被强制写死了。前提是句柄是基类
#include <iostream>
using namespace std;
class People
{
public:
virtual void sleep() = 0; // 纯虚函数,说明该类是抽象类,不能创建对象
virtual void say(){ //虚函数,该方法子类可以重写
cout << "people say" << endl;
}
void read(){ //普通函数,子类如果重写,那么用People做句柄,执行的依然是基类
cout << "People read" << endl;
}
};
class Student :public People{
public:
void sleep(){
cout << "Student sleep" << endl;
}
void say(){
cout << "Student say" << endl;
}
void read(){
cout << "Student read" << endl;
}
};
int main()
{
People *stu = new Student;
stu->read();
stu->say();
stu->sleep();
Student *stu1 = new Student;
stu1->read();
stu1->say();
stu1->sleep();
delete stu;
delete stu1;
return 0;
}
执行的结果可以看出来,普通函数会固定的执行基类的方法,而不是子类的方法。
还有Java中有GC机制, 所以基本上不需要用户来手动的回收内存,但是C++中却不同,在创建对象的时候,有两种方式
一种就是通过new,在java中基本上所以自己创建的类生成对象都是要用new,而C++中的new和java中的new就不同了。这点一开始很不适用。另一种方式跟java的new方式很像,只是没有new关键字。所以这里C++中就出现一个另一个函数,析构函数
而一般情况下,析构函数是虚函数,这是因为,在我们写程序过程中,经常使用多态,所以基类的析构函数不是虚函数,那么在完成内存回收的时候,会调用基类的析构函数,而不调用自类的析构函数,很容易造成内存泄漏。
C++中子类执行完析构函数,会自动的执行基类的析构函数。
如果基本的析构函数不是虚函数,那么例子如下
#include <iostream>
using namespace std;
class People
{
public:
~People(){
cout << "people delete" << endl;
}
virtual void sleep() = 0; //
virtual void say(){
cout << "people say" << endl;
}
void read(){
cout << "People read" << endl;
}
};
class Student :public People{
public:
~Student(){
cout << "student delete" << endl;
}
void sleep(){
cout << "Student sleep" << endl;
}
void say(){
cout << "Student say" << endl;
}
void read(){
cout << "Student read" << endl;
}
};
int main()
{
People *stu = new Student;
stu->read();
stu->say();
stu->sleep();
cout << "----------------------------------------------" << endl;
Student *stu1 = new Student;
stu1->read();
stu1->say();
stu1->sleep();
cout << "----------------------------------------------" << endl;
delete stu;
delete stu1;
return 0;
}
执行结果可以看出stu没有执行子类的析构函数,只执行了基类的析构函数。
如果将基类的析构函数变成虚函数,那么执行结果如下:
所以从这里知道,一般情况下,基类的析构函数是需要设置为虚函数的,而且子类执行完析构函数会自动执行基类的析构函数的。那么构造函数呢,我们再来看一下
在C++中构造函数是不能为虚函数的,因为所有的构造函数都是用来构造对象的,而虚函数是为了让通过用基类的指针,动态绑定的决定执行谁的方法。而在执行构造函数执行之前是没有对象存在的。所以也就没有任何意义。
而子类和基类的构造函数执行顺序呢?
#include <iostream>
using namespace std;
class People
{
public:
People(){
cout << "peopeo new" << endl;
}
virtual ~People(){
cout << "people delete" << endl;
}
virtual void sleep() = 0; //
virtual void say(){
cout << "people say" << endl;
}
void read(){
cout << "People read" << endl;
}
};
class Student :public People{
public:
Student(){
cout << "student new" << endl;
}
~Student(){
cout << "student delete" << endl;
}
void sleep(){
cout << "Student sleep" << endl;
}
void say(){
cout << "Student say" << endl;
}
void read(){
cout << "Student read" << endl;
}
};
int main()
{
People *stu = new Student;
stu->read();
stu->say();
stu->sleep();
cout << "----------------------------------------------" << endl;
Student *stu1 = new Student;
stu1->read();
stu1->say();
stu1->sleep();
cout << "----------------------------------------------" << endl;
delete stu;
delete stu1;
return 0;
}
执行的结果可以看出,在执行子类的构造函数之前会先执行基类的构造函数
以上就是C++中构造函数,析构函数,纯虚函数,虚函数和普通函数的区别。
总结:纯虚函数类似于java中抽象函数,只是在虚函数定义后加上=0,而java中是只定义即可。
基类析构函数一般是虚函数,执行完子类的析构函数后会自动执行基类的析构函数。
构造函数不可能是虚函数的,没有意义,执行构造函数的时候,会先执行基类的构造函数再执行子类的构造函数。