实验5 继承和多态
1. 实验任务1
验证性实验:编译时多态(静态绑定)vs. 运行时多态(动态绑定)
这个练习模拟出版物的分类,涵盖了类的组合、继承、运行时多态。
代码:
publisher.hpp
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 6 using std::cout; 7 using std::endl; 8 using std::string; 9 10 //发行/出版物类:publisher(抽象类) 11 class Publisher{ 12 public: 13 Publisher(const string &s = ""); 14 15 public: 16 virtual void publish() const = 0; //纯虚函数,作为接口继承 17 virtual void use() const = 0; 18 19 protected: 20 string name; //发行/出版物名字 21 }; 22 23 Publisher::Publisher(const string &s) : name{s} {} 24 25 //图书类 26 class Book : public Publisher{ 27 public: 28 Book(const string &s = "", const string &a = ""); //构造函数 29 30 public: 31 void publish() const override; 32 void use() const override; //接口 33 34 private: 35 string author; 36 }; 37 38 Book::Book(const string &s, const string &a) : Publisher{s}, author{a} { 39 } 40 41 void Book::publish() const{ 42 cout << "Publishing book: 《" << name << "》by " << author <<endl; 43 } 44 45 void Book::use() const{ 46 cout << "Reading book: 《" << name << "》by " << author <<endl; 47 } 48 49 50 //电影类:Film 51 class Film : public Publisher{ 52 public: 53 Film(const string &s = "", const string &d = ""); //构造函数 54 55 public: 56 void publish() const override; 57 void use() const override; 58 59 private: 60 string director; 61 }; 62 63 Film::Film(const string &s, const string &d) : Publisher{s}, director{d} {} 64 65 void Film::publish() const{ 66 cout << "Publishing Film: " << name << "directed by " << director <<endl; 67 } 68 69 void Film::use() const{ 70 cout << "Watching film: " << name << "directed by " << director <<endl; 71 } 72 73 74 75 //音乐类:Music 76 class Music : public Publisher{ 77 public: 78 Music(const string &s = "", const string &a = ""); //构造函数 79 80 public: 81 void publish() const override; 82 void use() const override; 83 84 private: 85 string artist; 86 }; 87 88 Music::Music(const string &s, const string &a) : Publisher{s}, artist{a} {} 89 90 void Music::publish() const{ 91 cout << "Publishing music <" << name << "by "<< artist <<endl; 92 } 93 94 void Music::use() const{ 95 cout << "Listening to music: " << name << " by " << artist << endl; 96 97 } 98 99
task1.cpp
1 #include "publisher.hpp" 2 #include <vector> 3 #include <typeinfo> 4 5 using std::vector; 6 7 void test(){ 8 vector<Publisher *> v; 9 10 v.push_back(new Book("Harry Potter", "J.K.Rowling")); 11 v.push_back(new Film("The Godfather", "Francis Ford Coppola")); 12 v.push_back(new Music("Blowing in the wind", "Bob Dylan")); 13 14 for(auto &ptr :v){ 15 cout << "pointer type:" << typeid(ptr).name() <<endl; //输出指针类 16 cout << "RTTI type:" << typeid(*ptr).name() <<endl; //输出指针指向的对象类型 17 18 ptr->publish(); 19 ptr->use(); 20 21 cout << endl; 22 } 23 } 24 25 int main(){ 26 test(); 27 }
正确编译后输出结果:
由运行测试结果可见,测试模块 test() 中
ptr是指向基类Publisher的指针变量。
ptr指向的对象( *ptr )的类型,是在运行时确定的。通过在基类中使用虚函数实现在运行时根据指针实际指向的对象调用相应的 publish 和 use 实现代码。
2. 实验任务2
验证性实验。
这个练习模拟图书销售统计,涵盖了类的组合、运算符重载、标准库(容器、算法)。
代码以多文件方式组织:
book.hpp 图书类Book定义
booksale.hpp 图书销售记录BookSale定义
task2.cpp 测试代码
book.hpp
1 #pragma once 2 3 #include <string> 4 #include <iostream> 5 #include <iomanip> 6 7 using std::string; 8 using std::ostream; 9 using std::endl; 10 using std::setw; 11 using std::left; 12 13 class Book{ 14 public: 15 Book(const string &name, const string &author, const string &translator, 16 const string &isbn, float price); 17 18 friend ostream& operator<< (ostream &out, const Book &book); 19 private: 20 string name; //书名 21 string author; //作者 22 string translator; //译者 23 string isbn; //isbn号 24 float price; //定价 25 26 }; 27 28 //成员函数实现 29 Book::Book(const string &name, const string &author, const string &translator, 30 const string &isbn, float price) { 31 this->name = name; 32 this->author = author; 33 this->translator = translator; 34 this->isbn = isbn; 35 this->price = price; 36 } 37 38 //友元实现 39 ostream& operator<< (ostream &out, const Book &book){ 40 out << left; 41 out << setw(15) << "书名:" << book.name << endl 42 << setw(15) << "作者:" << book.author << endl 43 << setw(15) << "译者:" << book.translator << endl 44 << setw(15) << "定价:" << book.price << endl; 45 46 return out; 47 } 48 49 50 51 52 53 54 55 56 57
booksale.hpp
1 #pragma once 2 3 #include "book.hpp" 4 #include <iostream> 5 #include <string> 6 #include <iomanip> 7 8 using std::string; 9 using std::cout; 10 using std::endl; 11 using std::setw; 12 13 class BookSale{ 14 public: 15 BookSale(const Book &b, float price, int amout); 16 int get_amount() const; 17 18 friend ostream& operator<<(ostream &out, const BookSale &item); 19 private: 20 Book rb; 21 float sales_price; //售价 22 int sales_amount; //销售数量 23 float revenue; //营收 24 }; 25 26 //成员函数实现 27 BookSale::BookSale(const Book &b, float price, int amount) :rb{b}, 28 sales_price{price}, sales_amount{amount}{ 29 revenue = sales_price * sales_amount; 30 } 31 32 int BookSale::get_amount() const{ 33 return sales_amount; 34 } 35 36 //友元函数实现 37 ostream& operator<<(ostream &out, const BookSale &item){ 38 out << left; 39 out << item.rb << endl 40 << setw(15) << "售价:" << item.sales_price << endl 41 << setw(15) << "销售数量:" << item.sales_amount << endl 42 << setw(15) << "营收:" << item.revenue ; 43 44 return out; 45 }
task2.cpp
1 #include "booksale.hpp" 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 #include <algorithm> 6 7 // 按图书销售数额比较 8 bool compare_by_amount(const BookSale &x1, const BookSale &x2) { 9 return x1.get_amount() > x2.get_amount(); 10 } 11 12 void test() { 13 using namespace std; 14 15 vector<BookSale> sales_lst; // 存放图书销售记录 16 17 int books_number; 18 cout << "录入图书数量: "; 19 cin >> books_number; 20 21 cout << "录入图书销售记录" << endl; 22 for(int i = 0; i < books_number; ++i) { 23 string name, author, translator, isbn; 24 float price; 25 cout << string(20, '-') << "第" << i+1 << "本图书信息录入" << string(20, '-') << endl; 26 cout << "录入书名: "; cin >> name; 27 cout << "录入作者: "; cin >> author; 28 cout << "录入译者: "; cin >> translator; 29 cout << "录入isbn: "; cin >> isbn; 30 cout << "录入定价: "; cin >> price; 31 32 Book book(name, author, translator, isbn, price); 33 34 float sales_price; 35 int sales_amount; 36 37 cout << "录入售价: "; cin >> sales_price; 38 cout << "录入销售数量: "; cin >> sales_amount; 39 40 BookSale record(book, sales_price, sales_amount); 41 sales_lst.push_back(record); 42 } 43 44 // 按销售册数排序 45 sort(sales_lst.begin(), sales_lst.end(), compare_by_amount); 46 47 // 按销售册数降序输出图书销售信息 48 cout << string(20, '=') << "图书销售统计" << string(20, '=') << endl; 49 for(auto &t: sales_lst) { 50 cout << t << endl; 51 cout << string(40, '-') << endl; 52 } 53 } 54 55 int main() { 56 test(); 57 }
正确录入后运行结果:
实验3
使用类的继承、多态,模拟简单的机器宠物。
问题场景描述如下:
对机器宠物进行抽象后,抽象出三个简单类:机器宠物类MachinePets、宠物猫类PetCats、宠物狗类
PetDogs。
pets:
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 6 using std::string; 7 using std::cout; 8 using std::endl; 9 10 //MachinePets类 11 class MachinePets{ 12 public: 13 MachinePets(const string &name):nickname{name} {} 14 string get_nickname() const; 15 virtual string talk() = 0; //纯虚函数,提供接口 16 private: 17 string nickname; 18 }; 19 20 //PetCats类 21 class PetCats : public MachinePets{ 22 public: 23 PetCats(const string &name):MachinePets{name} {} 24 string talk() override; 25 }; 26 27 //cat成员函数实现 28 string PetCats::talk(){ 29 return "miao wu ~"; 30 } 31 32 //PetDogs类 33 class PetDogs : public MachinePets { 34 public: 35 PetDogs(const string &name) : MachinePets{name} {} 36 string talk() override; 37 }; 38 39 //dog成员函数实现 40 string PetDogs::talk(){ 41 return "wang ~"; 42 }
task3.cpp
1 #include <iostream> 2 #include <vector> 3 #include "pets.hpp" 4 5 void test() { 6 using namespace std; 7 8 vector<MachinePets *> pets; 9 10 pets.push_back(new PetCats("miku")); 11 pets.push_back(new PetDogs("da huang")); 12 13 for(auto &ptr: pets) 14 cout << ptr->get_nickname() << " says " << ptr->talk() << endl; 15 } 16 17 int main() { 18 test(); 19 }
运行结果:
4. 实验任务4
设计并实现电影类Film,支持以下要求:
电影信息包括:片名、导演、制片国家/地区、上映年份
重载运算符>>,支持使用cin输入影片锡尼希
重载运算符<<,支持使用cout输出影片信息
其它成员函数,根据测试模块,按需设计并实现
代码以多文件方式组织:
film.hpp 类Film实现
task4.cpp 测试代码
film.cpp
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 #include <iomanip> 6 7 using std::left; 8 using std::string; 9 using std::cout; 10 using std::endl; 11 using std::istream; 12 using std::ostream; 13 using std::setw; 14 15 class Film{ 16 public: 17 //构造函数 18 Film( const string &name = " ", const string &director = " ", 19 const string &area = " ",int year = 0); 20 int get_year() const { 21 return year; 22 } 23 24 //重载运算符 25 friend istream& operator>>(istream &in, Film &f) ; 26 friend ostream& operator<<(ostream &out, Film &f) ; 27 28 private: 29 string name; //片名 30 string director; //导演 31 string area; //制片国家/地区 32 int year; //上映年份 33 }; 34 35 //成员函数实现 36 Film::Film( const string &name,const string &director, 37 const string &area,int year) { 38 39 this->name = name; 40 this->director = director; 41 this->area = area; 42 this->year = year; 43 } 44 45 //运算符重载 46 //cin 47 istream& operator>>(istream &in, Film &f) { 48 cout << "片名:" ; in >> f.name; 49 cout << "导演:" ; in >> f.director; 50 cout << "制片国家/地区:" ; in >> f.area; 51 cout << "上映年份:" ; in >> f.year; cout << endl; 52 53 } 54 55 //cout 56 ostream& operator<< (ostream &out, Film &f) { 57 out << left; 58 out << setw(15) << f.name 59 << setw(15) << f.director 60 << setw(15) << f.area 61 << setw(15) << f.year << endl; 62 63 }
task4.cpp
1 #include "film.hpp" 2 3 #include <iostream> 4 #include <vector> 5 #include <string> 6 #include <algorithm> 7 8 bool compare_by_year(const Film &x1, const Film &x2) { 9 return x1.get_year() > x2.get_year(); 10 } 11 void test(){ 12 using namespace std; 13 14 int n; 15 cout << "输入电影数目:"; 16 cin >> n; 17 18 cout << "录入" << n << "部电影信息" << endl; 19 vector<Film> film_list; 20 21 //录入电影信息 22 int i; 23 for(i = 0; i < n; i++){ 24 Film f; 25 cout << string(20,'-') << "第" << i+1 << "部电影录入" 26 << string(20,'-') <<endl; 27 28 cin >> f; 29 film_list.push_back(f); 30 } //for 31 32 //按发行年份升序排列 33 sort(film_list.begin(), film_list.end(),compare_by_year); 34 35 //输出 36 cout << string(20,'-') + "电影信息(按发行年份)" + 37 string(20,'-') <<endl; 38 for(auto &f : film_list) 39 cout << f << endl; 40 } 41 42 int main(){ 43 test(); 44 }
正确录入后,输出结果:
5. 实验任务5
自定义一个简化版类模板Complex, 实现类似C++标准库中的complex类模板,支持对类型的参数化。具
体要求如下:
对模板类重载运算符,支持如下操作:
c1 += c2
c1 + c2
c1 == c2
标准输入流提取运算,如cin >> c1 >> c2
标准输出流插入运算,cout << c1 << c2
33代码采用多文件方式组织:
Complex.hpp 模板Complex定义
task5.cpp 测试模块, main
Complex.hpp
1 #include<iostream> 2 3 using namespace std; 4 template <typename T> 5 class Complex{ 6 public: 7 Complex(T r=0,T i=0):real{r},imag{i}{} 8 T get_real()const{return real;} 9 T get_imag()const{return imag;} 10 Complex operator+(const Complex& c1)const{ 11 return Complex(real+c1.real,imag+c1.imag); 12 } 13 Complex& operator+=(const Complex &c){ 14 real += c.real; 15 imag += c.imag; 16 return *this; 17 } 18 bool operator==(const Complex& c1)const{ 19 return(c1.real==real && c1.imag==imag); 20 } 21 friend istream& operator>>(istream &in,Complex &c){ 22 in>>c.real>>c.imag; 23 return in; 24 } 25 friend ostream& operator<<(ostream &out,const Complex &c){ 26 out<<c.real<<" + "<<c.imag<<"i"<<endl; 27 return out; 28 } 29 private: 30 T real,imag; 31 };
task5.cpp
1 #include "Complex.hpp" 2 #include <iostream> 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 using std::boolalpha; 8 9 void test1() { 10 Complex<int> c1(2, -5), c2(c1); 11 12 cout << "c1 = " << c1 << endl; 13 cout << "c2 = " << c2 << endl; 14 cout << "c1 + c2 = " << c1 + c2 << endl; 15 16 c1 += c2; 17 cout << "c1 = " << c1 << endl; 18 cout << boolalpha << (c1 == c2) << endl; 19 } 20 21 void test2() { 22 Complex<double> c1, c2; 23 cout << "Enter c1 and c2: "; 24 cin >> c1 >> c2; 25 cout << "c1 = " << c1 << endl; 26 cout << "c2 = " << c2 << endl; 27 28 cout << "c1.real = " << c1.get_real() << endl; 29 cout << "c1.imag = " << c1.get_imag() << endl; 30 } 31 32 int main() { 33 cout << "自定义类模板Complex测试1: " << endl; 34 test1(); 35 36 cout << endl; 37 38 cout << "自定义类模板Complex测试2: " << endl; 39 test2(); 40 }
正确编写后,运行结果如下: