【C++】多态与RTTI实验

项目要求

  1. 要有相同的属性(成员变量)和行为(成员函数)。
  2. 都可以实现某一功能,但是实现的细节不一样。
  3. 两个子类要有完全不同的、各自特有的行为。
  4. 在 main 函数中通过一个基类指针数组来指向所有的派生类对象,然后通过遍历该数组调用上述所有函数,并能显示构造函数、析构函数的调用细节。

任务.png

解题源码

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
//Animal.h
#include<iostream>
#include<string>
using namespace std;
#pragma once
class Animal {
public:
Animal(string str) :name(str) { cout << "Creating Animal" << endl; }
void Eat();
virtual void Speak() = 0;//接口,图中斜体是接口,后面必须要填充,否则会报抽象类错误。
virtual ~Animal();
protected:
string name;//图中带#的是protected的
};//基类

class Dog :public Animal {
public:
Dog(string str) : Animal(str) { cout << "Creating Dog named " << name << endl; }
void Speak();
void Run();
~Dog();
};

class Bird :public Animal {
public:
Bird(string str);
void Speak();
void Fly();
~Bird();
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Animal.cpp
#include "Animal.h"

void Animal::Eat() { cout << name << " eating" << endl; }
void Animal::Speak() { cout << name << " speaking" << endl; }
Animal::~Animal() { cout << "Destroying Animal" << endl; }

void Dog::Speak() { cout << name << " barking!" << endl; };
void Dog::Run() { cout << name << " runing!" << endl; }
Dog::~Dog() { cout << "Destroying Dog named " << name << endl; }

Bird::Bird(string str) :Animal(str) { cout << "Creating Bird named " << name << endl; }
void Bird::Speak() { cout << name << " speaking!" << endl; }
void Bird::Fly() { cout << name << " flying!" << endl; }
Bird::~Bird() { cout << "Destroying Bird named " << name << endl; }
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
//main.cpp
#include"Animal.h"

int main() {
srand(time(0));//根据时间生成随机数种子
const int SIZE = 4;
Animal* allAnimals[SIZE];//基类指针数组
for (int i = 0; i < SIZE; i++)
if (rand() % 2 == 0)//随机一个数,根据单双数生成
allAnimals[i] = new Dog("dog" + to_string(i));//堆中生成,名字后面加了序号。to_string()能直接把任意类型转成字符串。
else
allAnimals[i] = new Bird("bird" + to_string(i));

for (Animal* pa : allAnimals) { //范围循环
pa->Speak();
pa->Eat();
if (typeid(*pa) == typeid(Dog)) {//判断类型
Dog* pd = dynamic_cast<Dog*>(pa);//把基类指针数组的类型转换成派生类,这样才会和堆中的数据对得上。
pd->Run();
}
else if (typeid(*pa) == typeid(Bird)) {
Bird* pb = dynamic_cast<Bird*>(pa);
pb->Fly();
}
}

for (int i = 0; i < SIZE; i++)
delete allAnimals[i];//释放堆中数据。
return 0;
}

问题

  1. RTTI 的基本含义是什么,通过哪些命令可以实现?
    • RTTI是“运行时类型识别”,它使程序能够获取由基类指针(引用)所指向的成员的实际派生类型。
    • 命令
      • dynamic_cast<type>(expression)
      • typeid(expression)
  2. 当使用基类指针指向派生类对象时,调用函数的规则是什么?
    • 先调用基类函数,后调用派生类函数
  3. C++提供几种强制类型转换?什么是向上类型转换、向下类型转换,本项目中使用了哪一个?
    • 4种。
    • 向上类型转换:将派生类转换成基类;向下类型转换:将基类转换为派生类
    • 本项目中使用了向下类型转换。
  4. 什么是多态,有几种类型的多态,各自的实现机制是什么?本项目中采用的是哪一种多态?
    • 多态:调用同名函数却因上下文不同会有不同实现的一种机制。
    • 2种
    • 静态多态:通过编译完成多态;动态多态:通过查找虚函数表完成多态
    • 动态多态