CPP学习之——虚函数应用拳击游戏(13.3)

一 应用场景

举个不太精确的例子,假设我们要射击一个拳击游戏,该游戏有好多角色,泰森、阿里、刘易斯或者霍利菲尔德;这些角色都具备一个共同的函数——出圈。但是不同的选手出拳的速度和力量不同,因此产生的效果不同。

二 示例演示及结果说明

2.1 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
using namespace std;
class poser
{
protected:
int age;
public:
virtual void beat() const {cout << "一般选手的力量为260磅" << endl;}

};
class Ali: public poser
{
virtual void beat() const {cout << "阿里一拳的力量为420磅" << endl;}
};
class Lewis: public poser
{
virtual void beat() const {cout << "刘易斯一拳的力量为480磅" << endl;}
};
class Tyson: public poser
{
virtual void beat() const {cout << "泰森一拳的力量为500磅" << endl;}
};
class Holy: public poser
{
virtual void beat() const {cout << "霍利菲尔德一拳的力量为350磅" << endl;}
};
int main()
{
poser *p[5];
poser *p1;
int choice, i;
for (int i = 0; i < 5; i++)
{
cout << "(1)阿里(2)刘易斯(3)泰森(4)霍利菲尔德:";
cin >> choice;
switch (choice)
{
case 1:
p1 = new Ali;
break;
case 2:
p1 = new Lewis;
break;
case 3:
p1 = new Tyson;
break;
case 4:
p1 = new Holy;
break;
default:
p1=new poser;
break;
}
p[i]=p1;
p[i]->beat();
}
return 0;
}

2.2 输出结果

1
2
3
4
5
6
7
(1)阿里(2)刘易斯(3)泰森(4)霍利菲尔德:1
阿里一拳的力量为420磅
(1)阿里(2)刘易斯(3)泰森(4)霍利菲尔德:2
刘易斯一拳的力量为480磅
(1)阿里(2)刘易斯(3)泰森(4)霍利菲尔德:5
一般选手的力量为260磅
(1)阿里(2)刘易斯(3)泰森(4)霍利菲尔德:

2.3 代码说明

  • 为了让不同的拳手(对象)调用相同的出拳(名字相同的函数)产生不同的效果(函数运行效果),我们将基类的beat()函数说明为virtual,也就是虚函数。因此程序执行时会自动判断对象,从而调用不同对象中的函数,该函数将会覆盖基类的同名函数

2.4 过程说明

  • 我们在main函数中假如了switch语句,来判断用户的每次输入,然后根据输入的数字在堆中创建不同派生类的对象(拳手)
  • 由于堆中的对象都是匿名的,而指向它们的指针(p1)只有一个,为了正确地找到它们,我们还要定义一个数组来接收每个指针(p1),因为对象(拳手)太多,不好区分,这里用数组a来接收每个指针(该指针p指向每个拳手)。最后通过数组的每个元素(指向不同拳手的指针)访问该对象(拳手)的函数(出拳)

2.5 注意点

  • 由于该程序运行不可能预测到用户输入哪个数字,是1、2、3还是4或者5,因此也不可能预先知道要调用哪个对象的函数,指针p是在我们输入一个数时才指向某个对象的。这就叫做动态联编或者运行时联编,相反假如再运行之前就确定好哪个指针指向哪个对象,而且在运行时不能更改的叫静态联编或者编译时联编。静态联编由于对象不用对自身进行跟踪,因此速度浪费比较小,而动态联编虽然可以动态追踪对象,灵活性比较强,但是速度浪费比较强,但是速度浪费也很严重。这就是两者的区别

2.6 知识点

  • 一个函数被说明为虚函数,在派生类中覆盖了该函数,那么该函数也是个虚函数,不过你也可以把它说明为虚函数,这样看起来更好懂些