1、多态的概念【重点】
-
同一操作(函数)作用于不同的对象(不同类实例化的对象),可以有不同的解释,产生不同的执行结果。【重点理解记忆】
-
在运行时,可以通过指向【基类的指针或者引用】,来调用实现派生类中的方法(派生类中的函数)。
2、虚函数(小重点,可以实现多态的关键)
1)虚函数是动态绑定的基础。用于继承关系中,它是在基类定义的【成员函数】,而且是【非静态成员函数】。
2)格式:
virtual 函数类型 函数名称(参数表){函数体}
【使用virtual关键字修饰的函数称为虚函数。如果在【基类】中的成员函数被声明为虚函数,也就意味着他在派生类中可能有不同的实现】
3)实例:
#include <iostream>
//多态的概念
//同一操作(函数)作用于不同的对象(不同类实例化的对象),可以有不同的解释,产生不同的执行结果
using namespace std;
//基类
class Person {
public:
//成员函数
virtual void Express_Love(void) //使用虚函数
{
cout << "I Love You!" << endl;
}
};
//派生类
class Chinese :public Person {
public:
//成员函数
void Express_Love(void)
{
cout << "俺稀罕你!" << endl;
}
};
class Russia :public Person {
public:
//成员函数
void Express_Love(void)
{
cout << "Я цябе кахаю!" << endl;
}
};
class Little_Japanese_devils :public Person {
public:
//成员函数
void Express_Love(void)
{
cout << "あなたのことが好きです!" << endl;
}
};
//同一操作
void function(Person &a)//使用基类的引用----作用于不同的对象
//(注意这个地方这里是引用,如果不使用引用的话,会造成派生类隐含转换为基类的情况【具体讲解看第五章集成中的第9小节】)
{
a.Express_Love(); //有不同的解释,产生不同的执行结果
}
int main()
{
Chinese person;
function(person);
Russia person1;
function(person1);
Little_Japanese_devils person2;
function(person2);
return 0;
}
运行结果:
俺稀罕你!
Я цябе кахаю!
あなたのことが好きです!
3、多态原理讲解:【重点】
-
当一个类中函数为虚函数时,该类实例化的对象存储就会在非静态成员的前面添加一个vfptr指针,该指针指向一个虚函数表,所以这个指针称为虚函数表指针。
-
虚函数表中存放的是当前对象的所有虚函数的地址。
(1)虚函数列表中存储结构为:【可以看出虚函数表中存放的都是基类中的函数地址,派生类可以重写这些地址】
long类型数组,以"\0"结尾;
(2)vfptr:有虚函数的对象有且只有一个vfptr指针,虚函数表中存放多个地址;
(3)虚函数表及vfptr是派生类对象的【基类产生的】--->派生类重写虚函数表内容【即重写地址】。
4、多态的条件
1)多态需要满足的条件:
-
有继承关系;
-
子类重写父类中的虚函数。
2)多态的使用条件:
父类的指针或者引用指向子类
4)多态重写的规则:
-
派生类中定义与基类虚函数同名、同参数、同返回值的成员函数。
-
在派生类中重新实现基类中的虚函数称为重写或覆盖。
-
多态是动态绑定。
5)多态的好处
-
将不同的子类对象都当做父类来看,可以写出通用代码。(一句话来概括:父亲的行为像儿子,而不是儿子的行为像父亲)
-
【提倡开闭原则:对于扩展进行开放,对于修改进行关闭。】
实例:
#include <iostream>
using namespace std;
//基类
class Basic_A {
public:
Basic_A(int a, int b) :A(a), B(b) //构造函数+初始化列表
{
}
//虚函数(实现一个加的功能)---通过派生类进行重写(覆盖写)
virtual int Make()
{
}
protected:
int A;
int B;
};
//派生类
class Derive_ADD:public Basic_A {
public:
//构造函数
Derive_ADD(int a, int b): Basic_A(a,b) //使用初始化列表来调用基类中的构造函数,进行赋值
{
}
int Make()
{
return A + B;
}
};
//派生类
class Derive_SUB:public Basic_A {
public:
//构造函数
Derive_SUB(int a, int b) : Basic_A(a, b) //使用初始化列表来调用基类中的构造函数,进行赋值
{
}
int Make()
{
return A - B;
}
};
//派生类
class Derive_MUL :public Basic_A {
public:
//构造函数
Derive_MUL(int a, int b) : Basic_A(a, b) //使用初始化列表来调用基类中的构造函数,进行赋值
{
}
int Make()
{
return A * B;
}
};
//派生类
class Derive_DIV :public Basic_A {
public:
//构造函数
Derive_DIV(int a, int b) : Basic_A(a, b) //使用初始化列表来调用基类中的构造函数,进行赋值
{
}
int Make()
{
return A / B;
}
};
int main()
{
//通过父类引用指向派生类
Derive_ADD add(10,5);
Basic_A& f = add;
cout <<"通过引用:"<<f.Make() << endl;
//通过父类的指针指向派生类
Basic_A* p = new Derive_MUL(10, 5);
cout <<"通过指针:"<<p->Make() << endl;
return 0;
}
运行结果:
通过引用:15
通过指针:50