-
-
[分享]C++基础十三-多态
-
发表于: 2021-9-29 17:28 8475
-
类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类和派生类之间才有意义,并且只能将派生类赋值给基类,在C++ 中称为向上转型(Upcasting)。
将派生类指针赋值给基类指针时,通过基类指针只能使用派生类的成员变量,不能使用派生类的成员函数,并不符合常规的逻辑习惯。为了让基类指针能够访问派生类的成员函数,C++ 增加了虚函数(Virtual Function),使用虚函数非常简单,只需要在函数声明前面增加virtual 关键字。
1、只需要在虚函数的声明处加上virtual 关键字,函数定义处可以加也可以不加。
2、可以只将基类中的函数声明为虚函数,这样所有派生类中具有函数覆盖关系的同名函数都将自动成为虚函数。
3、当在基类中定义了虚函数时,如果派生类没有定义新的函数覆盖此函数,那么将使用基类的虚函数。
4、虚函数是根据指针的指向来调用的,指针指向哪个类的对象就调用哪个类的虚函数。
5、构造函数不能是虚函数,派生类不继承基类的构造函数,将构造函数声明为虚函数没有什么意义,它仅仅是在派生类构造函数中被调用。
6、析构函数可以声明为虚函数,而且有时候必须要声明为虚函数。
有了虚函数,基类指针指向基类对象时就使用基类的成员,指向派生类对象时就使用派生类的成员,基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现方式,这种现象称为多态(Polymorphism)。
具体来说,有一对继承关系的两个类,这两个类中都有一个函数且名字、参数、返回值相同,不同类对象通过调用同一函数产生不同的行为,完成不同的事件。
多态的目的是为了通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行全方位的访问,尤其是成员函数,如果没有多态,我们只能访问成员变量。
1、必须存在继承关系。
2、继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)。
3、存在基类的指针或者引用,通过该指针或者引用调用虚函数。
首先看成员函数所在的类是否会作为基类,然后看成员函数在类的继承后有无可能需要更改功能,如果希望更改其功能的,一般应该将它声明为虚函数,如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不用声明为虚函数。
将析构函数定义为虚函数的原因:
因为基类指针可能指向派生类,当delete 的时候,如果析构函数不定义为虚函数,系统会直接调用基类的析构函数,这个时候派生类中可能就有一部分内存没有被释放,就会造成内存泄漏问题。
如果定义为虚析构,那么根据多态就会先调用派生类的析构函数,然后派生类的析构函数会自动调用基类的析构函数,保证内存释放的准确性。
#pragma once
class
CAnimal
{
public:
CAnimal(
int
nAge
=
0
,
int
dbWeight
=
0
);
~CAnimal();
void EatAndDrink();
void virtual Sleep();
void virtual ShowInfo();
protected:
int
m_nAge;
int
m_dbWeight;
};
class
CDog :public CAnimal
{
public:
CDog(
int
nAge
=
0
,
int
dbWeight
=
0
, char
*
szBelong
=
(char
*
)
"canine"
);
~CDog();
void SetBelong(char
*
szBelong);
char
*
GetBelong();
void EatAndDrink();
void Sleep();
void Bark();
void ShowInfo();
private:
char m_szBelong[
128
];
};
#pragma once
class
CAnimal
{
public:
CAnimal(
int
nAge
=
0
,
int
dbWeight
=
0
);
~CAnimal();
void EatAndDrink();
void virtual Sleep();
void virtual ShowInfo();
protected:
int
m_nAge;
int
m_dbWeight;
};
class
CDog :public CAnimal
{
public:
CDog(
int
nAge
=
0
,
int
dbWeight
=
0
, char
*
szBelong
=
(char
*
)
"canine"
);
~CDog();
void SetBelong(char
*
szBelong);
char
*
GetBelong();
void EatAndDrink();
void Sleep();
void Bark();
void ShowInfo();
private:
char m_szBelong[
128
];
};
#include "Animal.h"
#include <iostream>
using namespace std;
CAnimal::CAnimal(
int
nAge,
int
dbWeight) :m_nAge(nAge), m_dbWeight(dbWeight)
{
}
CAnimal::~CAnimal()
{
}
void CAnimal::EatAndDrink()
{
cout <<
"animal eat and drink"
<< endl;
}
void CAnimal::Sleep()
{
cout <<
"animal sleep"
<< endl;
}
void CAnimal::ShowInfo()
{
cout <<
"animal:age="
<< m_nAge <<
",weight="
<< m_dbWeight << endl;
}
CDog::CDog(
int
nAge,
int
dbWeight, char
*
szBelong) :CAnimal(nAge, dbWeight)
{
memset(m_szBelong,
0
,
128
);
strcpy_s(m_szBelong, szBelong);
}
CDog::~CDog()
{
memset(m_szBelong,
0
,
128
);
}
void CDog::SetBelong(char
*
szBelong)
{
memset(m_szBelong,
0
,
128
);
strcpy_s(m_szBelong, szBelong);
}
char
*
CDog::GetBelong()
{
return
m_szBelong;
}
void CDog::EatAndDrink()
{
cout <<
"dog eat and drink"
<< endl;
}
void CDog::Sleep()
{
cout <<
"dog sleep"
<< endl;
}
void CDog::Bark()
{
cout <<
"dog wangwang"
<< endl;
}
void CDog::ShowInfo()
{
cout <<
"dog:belong="
<< m_szBelong <<
",age="
<< m_nAge <<
",weight="
<< m_dbWeight << endl;
}
#include "Animal.h"
#include <iostream>
using namespace std;
CAnimal::CAnimal(
int
nAge,
int
dbWeight) :m_nAge(nAge), m_dbWeight(dbWeight)
{
}
CAnimal::~CAnimal()
{
}
void CAnimal::EatAndDrink()
{
cout <<
"animal eat and drink"
<< endl;
}
void CAnimal::Sleep()
{
cout <<
"animal sleep"
<< endl;
}
void CAnimal::ShowInfo()
{
cout <<
"animal:age="
<< m_nAge <<
",weight="
<< m_dbWeight << endl;
}
CDog::CDog(
int
nAge,
int
dbWeight, char
*
szBelong) :CAnimal(nAge, dbWeight)
{
memset(m_szBelong,
0
,
128
);
strcpy_s(m_szBelong, szBelong);
赞赏
- [分享]C++基础十七-异常机制 8576
- [分享]C++基础十六-模板 8939
- [分享]C++基础十五-运算符重载 8962
- [分享]C++基础十四-抽象类 8675
- [分享]C++基础十三-多态 8476