【实验四】继承

目录

任务2

task2.cpp

#include <iostream>
#include <typeinfo>

// definitation of Graph
class Graph
{
public:
    void draw() { std::cout << "Graph::draw() : just as an interface\n"; }
};


// definition of Rectangle, derived from Graph
class Rectangle : public Graph
{
public:
    void draw() { std::cout << "Rectangle::draw(): programs of draw a rectangle\n"; }
};


// definition of Circle, derived from Graph
class Circle : public Graph
{
public:
    void draw() { std::cout << "Circle::draw(): programs of draw a circle\n"; }
};


// definitaion of fun(): as a call interface
void fun(Graph *ptr)
{
    std::cout << "pointer type: " << typeid(ptr).name() << "\n";
    std::cout << "RTTI type: " << typeid(*ptr).name() << "\n";
    ptr -> draw();
}

// test 
int main()
{
    Graph g1;
    Rectangle r1;
    Circle c1;

    // call by object name
    g1.draw();
    r1.draw();
    c1.draw();

    std::cout << "\n";

    // call by object name, and using the scope resolution operator::
    r1.Graph::draw();
    c1.Graph::draw();

    std::cout << "\n";

    // call by pointer to Base class
    fun(&g1);
    fun(&r1);
    fun(&c1);
}

运行结果:
【实验四】继承

对代码稍作改动,在基类Graph的成员函数draw()前面加一个关键字virtual,重新编译运行程序

// definitation of Graph
class Graph
{ 
public:
	// 声明时加了关键字virtual
	virtual void draw() { std::cout << "Graph::draw() : just as aninterface\n"; }
};

运行结果:
【实验四】继承

加 virtual 之前, 派生类中与基类的同名函数实行的是覆盖隐藏, 但依旧可以通过二元作用域分辨符访问到基类的函数;
加 virtual 之后, 派生类中实现基类的同名函数定义, 此时即使是通过二元作用域分辨符访问基类的函数, 函数体也依旧是派生类中实现的.+66+

任务3

使用类的组合和继承模拟简单的车辆信息管理。
问题场景描述如下:
为了对车量基本信息进行管理,对现实世界车量基本信息抽象后,抽象出Car类、ElectricCar类、Battery类,它们之间的关系描述如下:ElectricCar类公有继承自Car类,ElectricCar中新增数据成员为Battery类对象。
类图简化模型如图所示。

【实验四】继承

  • 基于以下描述设计并实现Battery类
    • 每个Battery类对象有如下信息:车载动力电池容量(capacity)
    • 要求Battery类提供成员函数实现以下要求:
      • 带有默认形参值的构造函数。实现Battery类对象的构造,在构造对象时对电池容量capacity进行初始化,默认参数值为70(单位: kWh)。
      • 返回当前电池容量的函数get_capacity()。
  • 基于以下描述设计并实现Car类
    • 每辆汽车有如下信息:制造商(maker), 型号(model), 生产年份(year), 行车里程数(odometers)。
    • 要求Car类提供成员函数实现以下要求:
      • 带参数的构造函数。实现Car类对象的构造,并在构造对象时实现对制造商、型号、生产年份的初始化。初始构造时,行车里程数总是0。
      • 显示车辆信息的函数info()。实现车辆信息显示输出,输出信息包括:制造商、型号、生产年份、当前行车里程数。
      • 更新行车里程数的函数update_odometers()。更新后的行车里程数通过参数传递。要求能对参数进行合理性检查,如果更新后的行车里程数值小于当前行车里程数,打印警告信息,提示更新数值有误。
  • 基于以下描述设计并实现ElectricCar类
    • ElectricCar类继承自Car类,新增数据成员电池(battery)。其中,battery是Battery类对象。
    • 带参数的构造函数。实现ElectricCar类对象的构造,并在构造时实现对制造商、型号、生产年份以及新增数据成员电池的初始化。初始构造时,行车里程数总是0。
    • 显示车辆信息info()。实现车辆信息显示输出,包括:制造商、型号、生产年份、当前行车里程数、当前电池容量。
  • 在主程序中测试设计的类。
  • 要求采用多文件组织代码,文件列表如下:

Car.hpp

#include <iostream>
#include <string>

using namespace std;

class Car
{
private:
	string maker;  //制造商
	string model;  //型号
	string year;   //生产年份
	int odometers; //行车里程数
public:
	Car(){};
	Car(string maker, string model, string year) : maker(maker), model(model), year(year), odometers(0){};

	void info()
	{
		cout << "制造商: " << maker << endl
			 << "型号: " << model << endl
			 << "生产年份: " << year << endl
			 << "行车里程数: " << odometers << endl;
	}

	void update_odometers(int odometers){
		this->odometers = odometers;
	}
};

Battery.hpp

#include <iostream>

using namespace std;

class Battery
{
private:
	int capacity; // (kWh)
public:
	Battery(){};
	Battery(int capacity): capacity(capacity){};
	
	int get_capacity(){
		return capacity;
	}
};

ElectricCar.hpp

#include "Car.hpp"
#include "Battery.hpp"

class ElectricCar: public Car
{
private:
	Battery battery;
public:
	ElectricCar(){};
	ElectricCar(string maker, string model, string year, Battery battery): Car(maker, model, year), battery(battery){};

	void info(){
		Car::info();
		cout << "电池: " << battery.get_capacity();
	}
};

test.cpp

#include "ElectricCar.hpp"

int main(){
	string maker = "SONATA";
	string model = "GB9417-88";
	string year = "2021.11.24";

	Battery bettery(150000);

	ElectricCar electricCar(maker, model, year, bettery);
	electricCar.info();

	return 0;
}

运行结果:
【实验四】继承

任务4

使用类的继承,模拟简单的机器宠物。
问题场景描述如下:
对机器宠物进行抽象后,抽象出三个简单的类:机器宠物类MachinePets、宠物猫类PetCats、宠物狗类PetDogs。
它们之间的关系如UML类图所示:

【实验四】继承

  • 设计并实现一个机器宠物类MachinePets。
    • 每个机器宠物有如下信息:昵称(nickname)
    • 每个机器宠物有如下成员函数:
      • 带参数的构造函数MachinePets(const string s),为机器宠物初始化昵称。
      • 虚函数string talk()为机器宠物派生类提供宠物叫声的统一接口。(关于虚函数,参考实验任务2)
  • 设计并实现电子宠物猫类PetCats,该类公有继承自MachinePets。每个电子宠物猫类有如下成员函数:
    • 带参数的构造函数PetCats(const string s),为机器宠物猫初始化昵称。
    • string talk(),返回电子宠物猫叫声。
  • 设计并实现电子宠物狗类PetDogs, 该类公有继承自MachinePets。每个电子宠物狗类有如下成员函数:
    • 带参数的构造函数PetCats(const string s),为机器宠物狗初始化昵称。
    • string talk(),返回电子宠物狗叫声。
  • 在主程序中,测试类。其中,在主程序中编写一个统一的接口函数void play(××),可以根据实参对象的类型,显示不同宠物叫声。

MachinePets.hpp

#include <string>
#ifndef MACHINEPETS_hpp
#define MACHINEPETS_hpp
using namespace std;

class MachinePets
{
private:
	string nickname;
public:
	MachinePets(){};
	MachinePets(const string nickname): nickname(nickname){};

	const string get_nickname(){
		return nickname;
	}

	virtual string talk(){
		return "none";
	};
};

#endif

PetCats.hpp

#include "MachinePets.hpp"
#ifndef PETCATS_HPP
#define PETCATS_HPP
class PetCats: public MachinePets
{
public:
	PetCats(){};
	PetCats(string cat_name): MachinePets(cat_name){};

	string talk(){
		return ("i am a cat, my name is" + get_nickname() + " miao~");
	}
};
#endif

PetDogs.hpp

#include "MachinePets.hpp"
#include <iostream>
#ifndef PETDOGS_HPP
#define PETDOGS_HPP
class PetDogs: public MachinePets
{
public:
	PetDogs(){};
	PetDogs(string dog_name): MachinePets(dog_name){};

	string talk(){
		return ("i am a dog, my name is" + get_nickname() + " wang~");
	}
};
#endif

test.cpp

#include <iostream>
#include "MachinePets.hpp"
#include "PetCats.hpp"
#include "PetDogs.hpp"
void play(MachinePets *ptr)
{
	std::cout << ptr->get_nickname() << " says " << ptr->talk() << std::endl;
}
int main()
{
	PetCats cat("miku");
	PetDogs dog("da huang");
	play(&cat);
	play(&dog);
}

运行结果:
【实验四】继承

上一篇:实验四 继承


下一篇:实验4 继承