实验5
实验任务1:
源代码publisher.hpp
1 #pragma once 2 #include<string> 3 4 class Publisher{ 5 public: 6 Publisher(const std::string &name_=""); 7 virtual ~Publisher()=default; 8 9 public: 10 virtual void publish() const=0; 11 virtual void use() const=0; 12 13 protected: 14 std::string name; 15 }; 16 17 class Book:public Publisher{ 18 public: 19 Book(const std::string &name_="",const std::string &author_=""); 20 21 public: 22 void publish() const override; 23 void use() const override; 24 25 private: 26 std::string author; 27 }; 28 29 class Film:public Publisher{ 30 public: 31 Film(const std::string &name_="",const std::string &director_=""); 32 33 public: 34 void publish() const override; 35 void use() const override; 36 37 private: 38 std::string director; 39 }; 40 41 class Music:public Publisher{ 42 public: 43 Music(const std::string &name_="",const std::string &artist_=""); 44 45 public: 46 void publish() const override; 47 void use() const override; 48 49 private: 50 std::string artist; 51 };
源代码publisher.cpp
1 #include<iostream> 2 #include<string> 3 #include "publisher.hpp" 4 5 Publisher::Publisher(const std::string &name_):name{name_}{} 6 7 Book::Book(const std::string &name_,const std::string &author_):Publisher{name_},author{author_}{} 8 9 void Book::publish() const{ 10 std::cout << "Publishing book 《" << name << "》 by" << author << '\n'; 11 } 12 13 void Book::use() const{ 14 std::cout << "Reading book 《" << name << "》 by" << author << '\n'; 15 } 16 17 Film::Film(const std::string &name_,const std::string &director_):Publisher{name_},director{director_}{} 18 19 void Film::publish()const{ 20 std::cout << "Publishing Film <" << name << "> directed by" << director << '\n'; 21 } 22 23 void Film::use()const{ 24 std::cout << "Watching Film <" << name << "> directed by" <<director << '\n'; 25 } 26 27 Music::Music(const std::string &name_,const std::string &artist_):Publisher{name_},artist{artist_}{} 28 29 void Music::publish()const{ 30 std::cout << "Publishing Music <" << name << "> by" << artist << '\n'; 31 } 32 33 void Music::use() const { 34 std::cout << "Listening to music <" << name << "> by" << artist << '\n'; 35 }
源代码task1.cpp
1 #include<memory> 2 #include<iostream> 3 #include<vector> 4 #include "publisher.hpp" 5 6 void test1(){ 7 std::vector<Publisher *> v; 8 9 v.push_back(new Book("Harry Potter","J.K. Rowling")); 10 v.push_back(new Film("The Godfather","Francis Ford Coppola")); 11 v.push_back(new Music("Blowing in the wind","Bob Dylan")); 12 for(Publisher *ptr:v){ 13 ptr->publish(); 14 ptr->use(); 15 std::cout << '\n'; 16 delete ptr; 17 } 18 } 19 20 void test2(){ 21 std::vector<std::unique_ptr<Publisher>> v; 22 v.push_back(std::make_unique<Book>("Harry Potter","J.K. Rowling")); 23 v.push_back(std::make_unique<Film>("The Godfather","Francis Ford Coppola")); 24 v.push_back(std::make_unique<Music>("Blowing in the wind","Bob Dylan")); 25 26 for(const auto &ptr:v){ 27 ptr->publish(); 28 ptr->use(); 29 std::cout << '\n'; 30 } 31 } 32 33 void test3(){ 34 Book book("A Philosophy of Software Design", "John Ousterhout"); 35 book.publish(); 36 book.use(); 37 } 38 39 int main(){ 40 std::cout << "运行时多态:纯虚函数、抽象类\n"; 41 std::cout << "\n测试1: 使用原始指针\n"; 42 test1(); 43 std::cout << "\n测试2: 使用智能指针\n"; 44 test2(); 45 std::cout << "\n测试3: 直接使用类\n"; 46 test3(); 47 }
运行结果截图:

问题1:
(1)Publisher类中声明了纯虚函数。依据:
virtual void publish() const=0;
virtual void use() const=0;
(2)不能,抽象类不能被实例化,编译器会报错。
问题2:
(1)void publish() const override;
void use() const override;
(2)
问题3:
(1)Publisher类型的指针
(2)Book类对象,Film类对象,Music类对象
(3)当通过基类指针删除派生类对象时,能保证先调用派生类的析构函数,再调用基类的析构函数。如果删除virtual,只会调用基类的析构函数,而不会调用派生类的析构函数,导致派生类特有的资源泄露。
实验任务2:
源代码book.hpp
1 #pragma once 2 #include<string> 3 4 class Book{ 5 public: 6 Book(const std::string &name_, 7 const std::string &author_, 8 const std::string &translator_, 9 const std::string &isbn_, 10 double price_); 11 friend std::ostream& operator<<(std::ostream &out,const Book &book); 12 13 private: 14 std::string name; 15 std::string author; 16 std::string translator; 17 std::string isbn; 18 double price; 19 };
源代码book.cpp
1 #include <iomanip> 2 #include <iostream> 3 #include <string> 4 #include "book.hpp" 5 6 Book::Book(const std::string &name_, 7 const std::string &author_, 8 const std::string &translator_, 9 const std::string &isbn_, 10 double price_):name{name_}, author{author_}, translator{translator_}, 11 isbn{isbn_}, price{price_} { 12 } 13 14 std::ostream& operator<<(std::ostream &out,const Book &book){ 15 using std::left; 16 using std::setw; 17 18 out << left; 19 out << setw(15) << "书名:" << book.name << '\n' 20 << setw(15) << "作者:" << book.author << '\n' 21 << setw(15) << "译者:" << book.translator << '\n' 22 << setw(15) << "ISBN:" << book.isbn << '\n' 23 << setw(15) << "定价:" << book.price; 24 25 return out; 26 }
源代码booksale.hpp
1 #pragma once 2 #include <string> 3 #include "book.hpp" 4 5 class BookSale{ 6 public: 7 BookSale(const Book &rb_, double sales_price_, int sales_amount_); 8 int get_amount() const; 9 double get_revenue() const; 10 11 friend std::ostream& operator<<(std::ostream &out,const BookSale &item); 12 13 private: 14 Book rb; 15 double sales_price; 16 int sales_amount; 17 };
源代码booksale.cpp
1 #include <iomanip> 2 #include <iostream> 3 #include <string> 4 #include "booksale.hpp" 5 6 BookSale::BookSale(const Book &rb_, 7 double sales_price_, 8 int sales_amount_): rb{rb_}, sales_price{sales_price_}, 9 sales_amount{sales_amount_} { 10 } 11 12 int BookSale::get_amount() const { 13 return sales_amount; 14 } 15 16 double BookSale::get_revenue() const { 17 return sales_amount * sales_price; 18 } 19 20 std::ostream& operator<<(std::ostream &out,const BookSale &item){ 21 using std::left; 22 using std::setw; 23 24 out << left; 25 out << item.rb << '\n' 26 << setw(15) << "售价:" << item.sales_price << '\n' 27 << setw(15) << "销售数量:" << item.sales_amount << '\n' 28 << setw(15) << "营收:" << item.get_revenue(); 29 return out; 30 }
源代码task2.cpp
1 #include "booksale.hpp" 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 #include <algorithm> 6 7 bool compare_by_amount(const BookSale &x1, const BookSale &x2) { 8 return x1.get_amount() > x2.get_amount(); 9 } 10 11 void test(){ 12 using namespace std; 13 vector<BookSale> sales_lst; 14 15 int books_number; 16 cout << "录入图书数量: "; 17 cin >> books_number; 18 cout << "录入图书销售记录" << endl; 19 for(int i = 0; i < books_number; ++i) { 20 string name, author, translator, isbn; 21 float price; 22 cout << string(20, '-') << "第" << i+1 << "本图书信息录入" << string(20, '-') << endl; 23 cout << "录入书名: "; cin >> name; 24 cout << "录入作者: "; cin >> author; 25 cout << "录入译者: "; cin >> translator; 26 cout << "录入isbn: "; cin >> isbn; 27 cout << "录入定价: "; cin >> price; 28 Book book(name, author, translator, isbn, price); 29 float sales_price; 30 int sales_amount; 31 cout << "录入售价: "; cin >> sales_price; 32 cout << "录入销售数量: "; cin >> sales_amount; 33 BookSale record(book, sales_price, sales_amount); 34 sales_lst.push_back(record); 35 } 36 37 sort(sales_lst.begin(), sales_lst.end(), compare_by_amount); 38 cout << string(20, '=') << "图书销售统计" << string(20, '=') << endl; 39 for(auto &t: sales_lst) { 40 cout << t << endl; 41 cout << string(40, '-') << endl; 42 } 43 } 44 45 int main(){ 46 test(); 47 }
运行结果截图:

问题1:
(1)两处,用于Book类型和BookSale类型
(2)out << item.rb << '\n'
问题2:
(1)先定义存储BookSale对象的容器,然后调用std::sort函数,自定义比较函数compare_by_amount实现按销售数量降序排序。
(2) std::sort(sales_lst.begin(), sales_lst.end(),
[](const BookSale& a, const BookSale& b) -> bool {
return a.get_amount() > b.get_amount();
});
实验任务3:
源代码task3_1.cpp
1 #include <iostream> 2 3 class A { 4 public: 5 A(int x0, int y0); 6 void display() const; 7 private: 8 int x, y; 9 }; 10 A::A(int x0, int y0): x{x0}, y{y0} { 11 } 12 void A::display() const { 13 std::cout << x << ", " << y << '\n'; 14 } 15 16 class B { 17 public: 18 B(double x0, double y0); 19 void display() const; 20 private: 21 double x, y; 22 }; 23 B::B(double x0, double y0): x{x0}, y{y0} { 24 } 25 void B::display() const { 26 std::cout << x << ", " << y << '\n'; 27 } 28 void test() { 29 std::cout << "测试类A: " << '\n'; 30 A a(3, 4); 31 a.display(); 32 std::cout << "\n测试类B: " << '\n'; 33 B b(3.2, 5.6); 34 b.display(); 35 } 36 37 int main(){ 38 test(); 39 }
运行结果截图:

源代码task3_2.cpp
1 #include <iostream> 2 #include <string> 3 4 template<typename T> 5 class X{ 6 public: 7 X(T x0, T y0); 8 void display(); 9 private: 10 T x, y; 11 }; 12 template<typename T> 13 X<T>::X(T x0, T y0): x{x0}, y{y0} { 14 } 15 template<typename T> 16 void X<T>::display() { 17 std::cout << x << ", " << y << '\n'; 18 } 19 void test() { 20 std::cout << "测试1: 用int实例化类模板X" << '\n'; 21 X<int> x1(3, 4); 22 x1.display(); 23 std::cout << "\n测试2: 用double实例化类模板X" << '\n'; 24 X<double> x2(3.2, 5.6); 25 x2.display(); 26 std::cout << "\n测试3: 用string实例化类模板X" << '\n'; 27 X<std::string> x3("hello", "oop"); 28 x3.display(); 29 } 30 int main() { 31 test(); 32 }
运行结果截图:

实验任务4:
源文件Pet.hpp
1 #pragma once 2 #include<string> 3 4 class MachinePet{ 5 public: 6 MachinePet(const std::string &nickname_=""):nickname{nickname_}{} 7 virtual ~MachinePet()=default; 8 public: 9 std::string get_nickname() const{ 10 return nickname; 11 } 12 virtual std::string talk() const=0; 13 protected: 14 std::string nickname; 15 }; 16 17 class PetCat:public MachinePet{ 18 public: 19 PetCat(const std::string &nickname_=""):MachinePet{nickname_}{} 20 std::string talk() const override{ 21 return "miao wu~"; 22 } 23 }; 24 25 class PetDog:public MachinePet{ 26 public: 27 PetDog(const std::string &nickname_=""):MachinePet{nickname_}{} 28 std::string talk() const override{ 29 return "wang wang~"; 30 } 31 };
源文件task4.cpp
1 #include <iostream> 2 #include <memory> 3 #include <vector> 4 #include "pet.hpp" 5 6 void test1() { 7 std::vector<MachinePet *> pets; 8 pets.push_back(new PetCat("miku")); 9 pets.push_back(new PetDog("da huang")); 10 for(MachinePet *ptr: pets) { 11 std::cout << ptr->get_nickname() << " says " << ptr->talk() << '\n'; 12 delete ptr; 13 } 14 } 15 16 void test2() { 17 std::vector<std::unique_ptr<MachinePet>> pets; 18 pets.push_back(std::make_unique<PetCat>("miku")); 19 pets.push_back(std::make_unique<PetDog>("da huang")); 20 for(auto const &ptr: pets) 21 std::cout << ptr->get_nickname() << " says " << ptr->talk() << '\n'; 22 } 23 24 void test3() { 25 const PetCat cat("miku"); 26 std::cout << cat.get_nickname() << " says " << cat.talk() << '\n'; 27 const PetDog dog("da huang"); 28 std::cout << dog.get_nickname() << " says " << dog.talk() << '\n'; 29 } 30 31 int main() { 32 std::cout << "测试1: 使用原始指针\n"; 33 test1(); 34 std::cout << "\n测试2: 使用智能指针\n"; 35 test2(); 36 std::cout << "\n测试3: 直接使用类\n"; 37 test3(); 38 }
运行结果截图:

实验任务5:
源代码Complex.hpp
1 #pragma once 2 #include<iostream> 3 4 template<typename T> 5 class Complex{ 6 public: 7 Complex():real(0),imag(0){ 8 } 9 Complex(T r,T i=0):real(r),imag(i){ 10 } 11 Complex(const Complex& other):real(other.real),imag(other.imag){ 12 } 13 14 T get_real() const {return real;} 15 T get_imag() const {return imag;} 16 17 Complex& operator+=(const Complex& other){ 18 real+=other.real; 19 imag+=other.imag; 20 return *this; 21 } 22 23 bool operator==(const Complex& other)const{ 24 return (this->real==other.real)&&(this->imag==other.imag); 25 } 26 27 friend Complex operator+(const Complex &c1,const Complex &c2){ 28 return Complex(c1.real+c2.real,c1.imag+c2.imag); 29 } 30 31 friend std::ostream& operator<<(std::ostream& out,const Complex<T>& c){ 32 if(c.imag>=0) 33 out << c.real << "+" << c.imag << 'i'; 34 else 35 out << c.real << "-" << -c.imag << 'i'; 36 return out; 37 } 38 39 friend std::istream& operator>>(std::istream& in,Complex<T>& c){ 40 in >> c.real >> c.imag; 41 return in; 42 } 43 44 private: 45 T real,imag; 46 };
源代码task5.cpp
1 #include <iostream> 2 #include "Complex.hpp" 3 4 void test1() { 5 using std::cout; 6 using std::boolalpha; 7 8 Complex<int> c1(2, -5), c2(c1); 9 cout << "c1 = " << c1 << '\n'; 10 cout << "c2 = " << c2 << '\n'; 11 cout << "c1 + c2 = " << c1 + c2 << '\n'; 12 13 c1 += c2; 14 cout << "c1 = " << c1 << '\n'; 15 cout << boolalpha << (c1 == c2) << '\n'; 16 } 17 18 void test2() { 19 using std::cin; 20 using std::cout; 21 22 Complex<double> c1, c2; 23 cout << "Enter c1 and c2: "; 24 cin >> c1 >> c2; 25 cout << "c1 = " << c1 << '\n'; 26 cout << "c2 = " << c2 << '\n'; 27 28 const Complex<double> c3(c1); 29 cout << "c3.real = " << c3.get_real() << '\n'; 30 cout << "c3.imag = " << c3.get_imag() << '\n'; 31 } 32 33 int main() { 34 std::cout << "自定义类模板Complex测试1: \n"; 35 test1(); 36 std::cout << "\n自定义类模板Complex测试2: \n"; 37 test2(); 38 }
运行结果截图:

实验总结:
本次实验了解了类模板的定义与实例化,理解运算符重载机制,知道了什么是抽象类,能够正确定义和使用,学会使用继承、虚函数、抽象类实现接口继承与运行时多态。在写实验任务4时,程序编译正常,但运行出现访问冲突,查阅资料后发现可能是别的打开的文件发生错误,而在这里崩溃,在新建空项目将代码放进去后发现程序能够正常运行。在进行任务5时发现友元函数在运算符重载中时能够保持类的封装性,并使复数运算简洁又高效。

浙公网安备 33010602011771号