多态是C++面向对象三大特性之一
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
动态多态实现分三步:(代码中具体步骤用 【】标识)
- 子类重写父类的虚函数(类内实现)
- .父类指针指向子类对象(类外实现)
- .用该指针调用子类虚函数(类外实现)
案例一:
实现代码框架是:
class Basic
{
public:
virtual void exeGame() = 0; // 纯虚函数
}
class TCSGame :public BasicGame //继抽象类 BasicGame
{
public:
virtual void exeGame() // 【步骤一】 重写虚函数
{
}
}
void test()
{
Basic *b = new TCSGame(); //【步骤二】父类指针指向子类对象
b->exeGame(); //【步骤三】 用该指针调用子类虚函数
// 注:用引用的方式也可以,因为引用的本质也是指针
}
具体实现代码
#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class BasicGame // 抽象类
{
public:
virtual void exeGame() = 0; // 纯虚函数
};
class TCSGame :public BasicGame //继抽象类 BasicGame
{
public:
TCSGame(string name) //构造函数
{
m_Name = name;
}
virtual void exeGame() // 【步骤一】 重写虚函数, virtual 可要可不要
{
cout << "运行游戏:" << m_Name << endl;
}
public:
string m_Name;
};
class WingGame :public BasicGame //继抽象类 BasicGame
{
public:
WingGame(string name) //构造函数
{
m_Name = name;
}
virtual void exeGame() // 【步骤一】 重写虚函数, virtual 可要可不要
{
cout << "运行游戏:" << m_Name << endl;
}
public:
string m_Name;
};
void test01()
{
BasicGame *game;
game = new TCSGame("贪吃蛇"); // 【步骤二】 父类指针指向子类TCSGame对象
game->exeGame(); // 【步骤三】:用该指针,调用子类的虚函数
cout << "****************" << endl;
game = new WingGame("魂斗罗"); // 【步骤二】 父类指针指向子类WingGame对象
game->exeGame();
return;
}
int main()
{
test01();
system("pause");
return 0;
}
说明:使用动态多态的好处是,组织结构很清晰,便于扩展和维护;如果不用多态,而是在一个类里面实现多种功能,比如 上面的两个游戏,如果数量多了会麻烦,而且可读性不好,而且对代码来说,尽量不要改动之前的代码。读者有兴趣可以不用多态实现上面的功能,对比一下。
注: 如果对多态 不是很了解 的话,建议先弄懂案例一,再看下面的
案例二
多态非常的灵活,可以在函数传参时实现多态的赋值(步骤2)
实现代码框架是:
class Basic
{
friend void func(Basic *b); //抽象类声明友元函数
public:
virtual void exeGame() = 0; // 纯虚函数
};
class TCSGame :public BasicGame //继抽象类 BasicGame
{
public:
virtual void exeGame() // 【步骤一】 重写虚函数
{
}
};
class WingGame :public BasicGame //继抽象类 BasicGame
{
public:
virtual void exeGame() // 【步骤一】 重写虚函数
{
}
};
void func(Basic *b){}
void test()
{
Basic *b = new TCSGame(); //【步骤二】父类指针指向子类对象
func(b) //【步骤三】 用该指针调用子类虚函数
// 注:用引用的方式也可以,因为引用的本质也是指针
}
具体实现代码:
#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class BasicGame
{
friend void func(BasicGame *b); // 这里声明全局友元函数,方便调用 成员变量
public:
virtual void exeGame() = 0; // 纯虚函数
};
class TCSGame :public BasicGame //继抽象类 BasicGame
{
public:
TCSGame(string name) {
m_Name = name;
}
virtual void exeGame() // 【步骤一】 重写虚函数
{
cout << "运行游戏:" << m_Name << endl;
}
public:
string m_Name;
};
class WingGame :public BasicGame //继抽象类 BasicGame
{
public:
WingGame(string name) {
m_Name = name;
}
virtual void exeGame() // 【步骤一】 重写虚函数
{
cout << "运行游戏:" << m_Name << endl;
}
public:
string m_Name;
};
void func(BasicGame *b) {
b->exeGame(); // 【步骤三】用父类指针调用子类的虚函数
};
void test()
{
BasicGame *b;
b = new TCSGame("贪吃蛇"); //【步骤二】父类指针指向子类对象
func(b); // 将 指针传入
b = new WingGame("魂斗罗"); //【步骤二】父类指针指向子类对象
func(b); // 将 指针传入
}
int main()
{
test();
system("pause");
return 0;
}
说明: 其实步骤二和步骤一是一样的,只不过多了一个传参而已;但是这种形式更加 方便;
案例三
既然 步骤2可以用函数传参 的方式实现,那么构造函数 使用该方式是没有问题的;
代码框架:
class Basic // 抽象类
{
public:
virtual void exeFunc() = 0; //纯虚函数
int A;
int B;
};
class exam1:public Basic // 继承抽象类
{
public:
exam1(int a, int b){} // 构造函数
void exeFunc(){} // 【步骤一】重写虚函数
};
class Act // 主类
{
public:
Act(Basic *b){} // 【步骤二】父类指针指向子类对象(传参)
public:
Basic *m_B; // 将一个类对象的成员变量
};
void test()
{
Basic *b = new exam1(10,20); // 【步骤二】父类指针指向子类对象
Act act = Act(b); // 【步骤二】父类指针指向子类对象(传参)
act.m_B->exeFunc();// 【步骤三】父类指针调用子类虚函数
}
具体实现代码如下:
#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class Basic
{
public:
virtual void exeFunc() = 0; //纯虚函数
int A;
int B;
};
class exam1 :public Basic // 继承抽象类
{
public:
exam1(int a, int b)
{
A = a;
B = b;
}
void exeFunc() // 【步骤一】重写虚函数
{
cout << "A=" << A << ",B=" << B << endl;
}
};
class Act
{
public:
Act(Basic *b) // 【步骤二】父类指针指向子类对象
{
m_B = b;
}
public:
Basic *m_B;
};
void test01()
{
Basic *b = new exam1(10, 20); // 【步骤二】父类指针指向子类对象
Act act = Act(b); // 【步骤二】父类指针指向子类对象(传参)
act.m_B->exeFunc();
}
int main()
{
test01();
system("pause");
return 0;
}
说明: 案例三,有 继承且 将 类对象做成员变量时,会很方便
如果以上都弄明白了,可以尝试一下下面这个案例:
代码如下
#include<iostream>
#include<string>
#include<map>
#include<stdlib.h>
#include <typeinfo>
using namespace std;
// 抽象cpu类
class CPU
{
public:
virtual void calculate() = 0;
};
class InterCPU:public CPU
{
public:
virtual void calculate()
{
cout << "InterCpu 开始工作" << endl;
}
};
class AMDCPU:public CPU
{
public:
virtual void calculate()
{
cout << "AMDCpu 开始工作" << endl;
}
};
// 抽象内存类
class Memory
{
public:
virtual void storage() = 0;
};
class InterMemory:public Memory
{
public:
virtual void storage()
{
cout << "InterMemory 开始工作" << endl;
}
};
class AMDMemory:public Memory
{
public:
virtual void storage()
{
cout << "AMDMemory 开始工作" << endl;
}
};
// 抽象cpu类
class VCard
{
public:
virtual void show() = 0;
};
class InterVCard :public VCard
{
public:
virtual void show()
{
cout << "InterCard 开始工作" << endl;
}
};
class AMDVCard:public VCard
{
public:
virtual void show()
{
cout << "AMDVCard 开始工作" << endl;
}
};
class Computer
{
public:
Computer(CPU *c, Memory *m, VCard *v, string name)
{
cpu = c;
mem = m;
vc = v;
this->name = name;
}
void work()
{
cout << name << "启动" << endl;
cpu->calculate();
mem->storage();
vc->show();
}
void mountWork(CPU *c, Memory *m, VCard *v) {
cout << name << "电脑启动加载硬件" << endl;
c->calculate();
m->storage();
v->show();
}
public:
CPU *cpu;
Memory *mem;
VCard *vc;
string name;
};
void test01()
{
InterVCard *interVc = new InterVCard();
AMDVCard *amdVc = new AMDVCard();
InterMemory *interMem = new InterMemory();
AMDMemory *amdMem = new AMDMemory();
InterCPU *interCpu = new InterCPU();
AMDCPU *amdCpu = new AMDCPU();
Computer huaweiCom = Computer(amdCpu, interMem, interVc, "华为电脑");
huaweiCom.work();
cout << "=========================" << endl;
Computer lenovoCom = Computer(interCpu, interMem, amdVc, "联想电脑");
lenovoCom.work();
cout << "=========================" << endl;
Computer huasuoCom = Computer(interCpu, interMem, interVc, "华所电脑");
huasuoCom.work();
cout << "=========================" << endl;
Computer xiaomiCom = Computer(amdCpu, amdMem, amdVc, "小米电脑");
xiaomiCom.work();
}
结尾: 以上就是本人对于多态的一些总结,如有不妥之处,请留言一起交流