//十六.虚函数以及多态相关
//参考parent3.h ,child31,child32
//父类指针指向子类对象或者父类引用指向子类对象。
//父类和子类中有相同的函数,(返回值,方法名, 参数列表完全一样)
//在相同的函数前面加上关键字virtual,就可以实现多态。
//加了virtural关键字的方法就是虚方法。
//注意 virtual 关键字一定是要加在 父类.h 的方法上,父类的.cpp上不加,子类上可加可不加。
parent3.h
#pragma once
#include
#include
using namespace std;
class Parent3 {
public:
int m_parent_age;
protected:
string m_parent_name;
private:
double m_parent_number;
public:
//构造方法
Parent3(int age, string name, double number);
public:
//虚方法,多态的方法
virtual void eat();
public:
//parent3独自拥有的public方法
void parentpubliceat();
protected:
//parent3独自拥有的 protected 方法
void parentprotectedeat();
private:
//parent3独自拥有的 private 方法
void parentprivateeat();
};
parent3.cpp
#include "parent3.h"
Parent3::Parent3(int age, string name, double number):m_parent_age(age),m_parent_name(name),m_parent_number(number)
{
cout << "Parent3 构造方法被执行" << endl;
}
//想要实现多态的函数
void Parent3::eat()
{
cout << "Parent3 eat方法被执行" << endl;
}
void Parent3::parentpubliceat()
{
cout << "Parent3 自己的public eat 方法" << endl;
}
void Parent3::parentprotectedeat()
{
cout << "Parent3 自己的 protected eat 方法" << endl;
}
void Parent3::parentprivateeat()
{
cout << "Parent3 自己的 private eat 方法" << endl;
}
child31.h
#pragma once
#include
#include
#include "parent3.h"
using namespace std;
class Child31 :public Parent3{
public:
int m_31childage;
string m_31childname;
double m_31childnumber;
public:
Child31(int childage,string childname,double childnumber,int parentage,string parentname,double parentnumber);
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
public:
void child31publiceat();
protected:
void child31protectedeat();
private:
void child31privateeat();
};
child31.cpp
#include "child31.h"
Child31::Child31(int childage, string childname, double childnumber,
int parentage, string parentname, double parentnumber)
:Parent3(parentage, parentname, parentnumber),
m_31childage(childage),m_31childname(childname),m_31childnumber(childnumber)
{
cout << "Child31构造方法执行" << endl;
}
void Child31::eat()
{
cout << "Child31 eat 方法执行" << endl;
}
void Child31::child31publiceat()
{
cout << "Child31 自己的 public 方法执行" << endl;
}
void Child31::child31protectedeat()
{
cout << "Child31 自己的 protected 方法执行" << endl;
}
void Child31::child31privateeat()
{
cout << "Child31 自己的 priavte 方法执行" << endl;
}
child32.h
#include "parent3.h"
using namespace std;
class Child32 :public Parent3 {
public:
int m_32childage;
string m_32childname;
double m_32childnumber;
public:
Child32(int childage, string childname, double childnumber, int parentage, string parentname, double parentnumber);
void eat() override;
public:
void child32publiceat();
protected:
void child32protectedeat();
private:
void child32privateeat();
};
child32.cpp
#include "child32.h"
Child32::Child32(int childage, string childname, double childnumber,
int parentage, string parentname, double parentnumber)
:Parent3(parentage, parentname, parentnumber),
m_32childage(childage),m_32childname(childname),m_32childnumber(childnumber)
{
cout << "Child32构造方法执行" << endl;
}
void Child32::eat()
{
cout << "Child32 eat 方法执行" << endl;
}
void Child32::child32publiceat()
{
cout << "Child32 自己的 public 方法执行" << endl;
}
void Child32::child32protectedeat()
{
cout << "Child32 自己的 protected 方法执行" << endl;
}
void Child32::child32privateeat()
{
cout << "Child32 自己的 priavte 方法执行" << endl;
}
main.cpp
#include "parent3.h"
#include "child31.h"
#include "child32.h"
void main() {
//多态 start
Parent3 *pa1 = new Child31(31, "child31", 99.9, 62, "parent3", 88.8);
cout << "111111" << endl;
pa1->eat();
cout << "222222" << endl;
Parent3 *pa2 = new Child32(32, "child32", 32.32, 64, "parent3", 64.64);
cout << "333333" << endl;
pa2->eat();
cout << "444444" << endl;
//多态end
//由于这时候 pa1的定义是 Parent3,因此只能访问 Parent3 的方法,
//且由于是main.cpp中访问(也就是说:在类外访问类),只能访问Parent3的public方法
pa1->parentpubliceat();
}
更重要的是,它会检查基类虚函数和派生类中重载函数的签名不匹配问题。如果签名不匹配,编译器会发出错误信息。
parent.h
public:
//虚方法,多态的方法
virtual void eat();
//想要实现多态的函数
void Parent3::eat()
{
cout << "Parent3 eat方法被执行" << endl;
}
child.h
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
void Child31::eat()
{
cout << "Child31 eat 方法执行" << endl;
}
如果不是 虚函数,则子类中不能使用
parent.h
public:
//不是虚函数
void aaa();
void Parent3::aaa()
{
cout << "parent aaa" << endl;
}
child.h
public:
Child31(int childage,string childname,double childnumber,int parentage,string parentname,double parentnumber);
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
void aaa() override;//build error ,aaa()方法需要是 虚函数
//十七. final关键字
//final 修饰类,则类不等被继承
class Parent4 final{}
//parent4.h child4.h
#pragma once
#include
#include
using namespace std;
//将类声明成final,则该类不能被继承
class Parent4 final {
public:
int m_parent_age;
protected:
string m_parent_name;
private:
double m_parent_number;
public:
//构造方法
Parent4();
Parent4(int age, string name, double number);
public:
//虚方法,多态的方法
virtual void eat();
};
#include "parent4.h"
using namespace std;
//严重性 代码 说明 项目 文件 行 禁止显示状态
//错误 C3246 “Child4” : 无法从“Parent4”继承,因为它已被声明为“final” 001for d : \allinformation\cpp\001for\001for\001for\child4.h 5
class Child4 :public Parent4 { //build error,Parent4类被设置为final,因此不能被继承
public:
Child4();
};
parent.h
public:
//final 必须修饰 virtual 的方法,表示该方法可以被继承,但是不能被重写
virtual void cannotextendsfunc() final;
parent.cpp
void Parent3::cannotextendsfunc()
{
cout << "parent cannotextendsfunc" << endl;
}
child.h
//build error,cannotextendsfunc被声明为final,无法重写。
//void cannotextendsfunc();
//build pass ,方法名一样,但是参数不一样,因此是child31自己写的一个新函数
//void cannotextendsfunc(int a );
main.cpp
// final 方法可以被继承,但是不能重写
Child31 ch31 = Child31(31, "child31", 99.9, 62, "parent3", 88.8);
ch31.cannotextendsfunc();//该 方法可以被继承,但是不能重写,因此会调用父类的 cannotextendsfunc方法
//纯虚函数 在.h中 声明,在.cpp中定义或者不定义都可以,因为子类都要实现该虚函数,且该类有了该 纯虚函数后,就变成了抽象类,抽象类无法初始化自己,因此也调用不到,这就是在.cpp中定义或者不定义都可以的原因。
parent.h
virtual void eat() = 0;
在这里我们在parent.cpp中 定义了 该纯虚函数。实验证明,不定义该纯虚函数也是一样的。
parent.cpp
//定义纯虚函数
void Parent5::eat()
{
cout << "Parent5 eat 方法被执行" << endl;
}
parent.h
#pragma once
#include
#include
using namespace std;
//如果类中有纯虚函数,该类就是抽象类,抽象类无法创建自己
class Parent5 {
public:
int m_parent_age;
protected:
string m_parent_name;
private:
double m_parent_number;
public:
//构造方法
Parent5();
Parent5(int age, string name, double number);
public:
//纯虚函数
virtual void eat() = 0;
void aaa();
};
parent.cpp
#include "parent5.h"
Parent5::Parent5(int age, string name, double number):m_parent_age(age),m_parent_name(name),m_parent_number(number)
{
cout << "Parent5 构造方法被执行" << endl;
}
Parent5::Parent5() {
cout << "Parent5 空构造方法被执行" << endl;
}
//定义纯虚函数
void Parent5::eat()
{
cout << "Parent5 eat 方法被执行" << endl;
}
void Parent5::aaa()
{
cout << "Parent5 aaa 方法被执行" << endl;
}
child51.h
#pragma once
#include
#include
#include "parent5.h"
using namespace std;
class Child51 :public Parent5{
public:
int m_51childage;
string m_51childname;
double m_51childnumber;
public:
Child51();
Child51(int childage,string childname,double childnumber,int parentage,string parentname,double parentnumber);
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
};
child51.cpp
#include "child51.h"
Child51::Child51()
{
cout << "child51 空的构造函数 " << endl;
}
Child51::Child51(int childage, string childname, double childnumber,
int parentage, string parentname, double parentnumber)
:Parent5(parentage, parentname, parentnumber),
m_51childage(childage),
m_51childname(childname),
m_51childnumber(childnumber)
{
cout<<"child51 构造函数 "<
child52.h
#pragma once
#include
#include
#include "parent5.h"
using namespace std;
class Child52 :public Parent5 {
public:
int m_52childage;
string m_52childname;
double m_52childnumber;
public:
Child52();
Child52(int childage, string childname, double childnumber, int parentage, string parentname, double parentnumber);
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
};
child52.cpp
#include "child52.h"
Child52::Child52()
{
cout << "child52 空的构造函数 " << endl;
}
Child52::Child52(int childage, string childname, double childnumber,
int parentage, string parentname, double parentnumber)
:Parent5(parentage, parentname, parentnumber),
m_52childage(childage),
m_52childname(childname),
m_52childnumber(childnumber)
{
cout << "child52 构造函数 " << endl;
}
void Child52::eat()
{
cout << "child52 eat 函数" << endl;
}
main.cpp
void main() {
//build error,原因是 "Parent5::eat" 是纯虚函数
//Parent5 pa;
// 在 child51 没有实现 eat 虚构函数的时候,Child51 无法建立对象,会有build error
//Child51 c51;
// 在 child51 没有实现 eat 虚构函数的时候,Child51 无法建立对象,会有build error
//Parent5 *pa = new Child51();
Child51 c51; // 在 child51 实现 eat 虚构函数后,OK
Parent5 *pa = new Child51();// 在 child51 实现 eat 虚构函数后,OK
pa->eat();//多态调用 child51的 eat函数
Parent5 *pa2 = new Child52();// 在 child52 实现 eat 虚构函数后,OK
pa2->eat();//多态调用 child52的 eat函数
}
parent.h
#pragma once
#include
#include
using namespace std;
//基类中的析构函数一般要写成 虚函数
class Parent6 {
public:
//构造方法
Parent6();
virtual ~Parent6();
public:
//纯虚函数
virtual void eat();
};
parent.cpp
#include "parent6.h"
Parent6::Parent6()
{
cout << "Parent6 构造函数 " << endl;
}
Parent6::~Parent6()
{
cout << "Parent6 析构函数 " << endl;
}
void Parent6::eat()
{
cout << "Parent6 eat函数" << endl;
}
child.h
#pragma once
#include
#include
#include "parent6.h"
using namespace std;
class Child6 :public Parent6 {
public:
Child6();
~Child6();
//以防止写错,可以使用override 关键字,使用后,如果父类没有eat方法,会有build error
void eat() override;
};
child.cpp
#include "child6.h"
Child6::Child6()
{
cout << "Child6 构造函数 " << endl;
}
Child6::~Child6()
{
cout << "Child6 析构函数 " << endl;
}
void Child6::eat()
{
cout << "Child6 eat函数 " << endl;
}
main.cpp
//十九 基类的析构函数一般需要写成纯函数
//parent6 和 child6
#include "child6.h"
void main() {
Parent6 *pa = new Child6();
pa->eat();
delete pa;
//在析构函数不是 虚函数时的 运行结果,我们会发现,并没有调用child6的析构函数
// Parent6 构造函数
// Child6 构造函数
// Child6 eat函数
// Parent6 析构函数
//原因 :: 这是因为 pa 在定义的时候,就是 Parent6 *,在delete的时候,会以这个为准。
//如果将 Parent6中的析构函数写成 虚函数,
//那么delete 的时候,就会变成运行时状态了,会看 new 后面的对象 也就是Child6。
//而子类的 析构函数的 调用顺序 ,是先调用子类的析构函数,然后调用父类的析构函数。
//解决方案:: 把 父类的析构函数写成 虚函数。
//改后的运行结果:
// Parent6 构造函数
// Child6 构造函数
// Child6 eat函数
// Child6 析构函数
// Parent6 析构函数
}