任务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);
}
运行结果: