实验五

任务一

publisher.hpp

 1 #pragma once
 2 #include<string>
 3 class Publisher
 4 {
 5     public:
 6         Publisher(const std::string &name_="");
 7         virtual ~Publisher()=default;
 8     public:
 9         virtual void publish() const=0;
10         virtual void use() const=0;
11     protected:
12             std::string name;            
13 };
14 class Book:public Publisher
15 {
16     public:
17         Book(const std::string &name_="",const std::string &author_="");
18     public:
19         void publish() const override;
20         void use() const override;
21     private:
22         std::string author;    
23 };
24 class Film:public Publisher
25 {
26     public:
27         Film(const std::string &name_="",const std::string &director_="");
28     public:
29         void publish() const override;
30         void use () const override;
31     private:
32         std::string director;
33 };
34 class Music:public Publisher
35 {
36     public:
37         Music(const std::string &name_="",const std::string &artist_="");
38     public:
39         void publish() const override;
40         void use() const override;
41     private:
42         std::string artist;        
43 };

publisher.cpp

 1 include<iostream>
 2 #include<string>
 3 #include"publisher.hpp"
 4 Publisher::Publisher(const std::string &name_): name{name_} 
 5 {
 6 }
 7 Book::Book(const std::string &name_,const std::string &author_):Publisher{name_},author{author_}
 8 {
 9 }
10 void Book::publish() const
11 {
12   std::cout<<"Publishing book 《"<<name<<"》by"<<author<<'\n'; 
13 }
14 void Book::use() const
15 {
16     std::cout<<"Reading book 《"<<name<<"》by"<<author<<'\n'; 
17 }
18 Film::Film(const std::string &name_,const std::string &director_):Publisher{name_},director{director_}
19 {
20 }
21 void Film::publish() const
22 {
23     std::cout<<"Publishing film<"<<name<<"> directed by"<<director<<'\n';
24 }
25 void Film::use()const
26 {
27  std::cout << "Watching film <" << name << "> directed by " << director << '\n';
28 }
29 Music::Music(const std::string &name_, const std::string &artist_): Publisher{name_}, 
30 artist{artist_}
31 {
32 }
33 void Music::publish() const
34 {
35  std::cout << "Publishing music <" << name << "> by " << artist << '\n';
36 }
37 void Music::use() const
38 {
39  std::cout << "Listening to music <" << name << "> by " << artist << '\n';
40 }

task1.cpp

 1 #include<memory>
 2 #include<iostream>
 3 #include<vector>
 4 #include"publisher.hpp"
 5 void test1()
 6 {
 7     std::vector<Publisher *> v;
 8     v.push_back(new Book("Harry Potter","J.K.Rowling"));
 9     v.push_back(new Film("The Godfather", "Francis Ford Coppola"));
10     v.push_back(new Music("Blowing in the wind", "Bob Dylan"));
11     for(Publisher *ptr:v)
12     {
13         ptr->publish();
14         ptr->use();
15         std::cout<<'\n';
16         delete ptr;
17      } 
18 }
19 void test2()
20 {
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   for(const auto &ptr: v) 
26   {
27   ptr->publish();
28   ptr->use();
29   std::cout << '\n';
30   }
31 }
32 void test3()
33 {
34     Book book("A Philosophy of Software Design","John Ousterhout");
35     book.publish() ;
36     book.use() ;
37 }
38  int main()
39 {
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:抽象类机制
(1)是什么决定了 Publisher 是抽象类?用一句话说明,并指出代码中的具体依据。
答:它包含纯虚函数,依据是类中声明:virtual void publish() const = 0; virtual void use() const = 0;
(2)如果在 main.cpp 里直接写 Publisher p; 能否编译通过?为什么?
答:不能,因为抽象类不能实例化
问题2:纯虚函数与接口继承
(1)Book 、Film 、Music 必须实现哪两个函数才能通过编译?请写出其完整函数声明。
答:这三个类中都必须实现void publish() const override;void use() const override;
(2) 在 publisher.cpp 的 Film 类实现中,把两个成员函数实现里的 const 去掉(保持函数体不变),重新编译,报错信息是什么?
答:函数与基类中的不匹配
问题3:运行时多态与虚析构
(1)在 test1() 里,for (Publisher *ptr : v) 中ptr 的声明类型是什么?
答:Publisher 类型的指针
(2)当循环执行到 ptr->publish(); 时,ptr 实际指向的对象类型分别有哪些?(按循环顺序写出)
答:Book,Film,Music
(3)基类 Publisher 的析构函数为何声明为virtual ?若删除 virtual ,执行 delete ptr; 会出 现什么问题
答:ptr可以调用派生类析构函数,若删除,无法调用派生类析构函数,部分派生类资源不被释放

 任务二

book.hpp

 1 #pragma once
 2 #include<string>
 3 class Book
 4 {
 5 public:
 6 Book(const std::string &name_,const std::string &author_,const std::string &translator_,const std::string &isbn_,double price_);
 7 friend std::ostream& operator<<(std::ostream &out,const Book &book);
 8 private:
 9 std::string name;
10 std::string author;
11 std::string translator;
12 std::string isbn;
13 double price;
14 };

book.cpp

 1 #include<iostream>
 2 #include<string>
 3 #include"book.hpp"
 4 Book::Book(const std::string &name_,const std::string &author_,const std::string &translator_,const std::string &isbn_,double price_):name{name_},author{author_},translator{translator_},isbn{isbn_},price{price_}
 5 {
 6 }
 7 std::ostream& operator<<(std::ostream &out,const Book &book)
 8 {
 9     using std::left;
10     using std::setw;
11     out<<left;
12     out<<setw(15)<<"书名:"<<book.name<<'\n'<<setw(15)<<"作者:"<<book.author<<'\n'<<setw(15) << "译者:" << book.translator << '\n'
13         << setw(15) << "ISBN:" << book.isbn << '\n'<< setw(15) << "定价:" << book.price; 
14     return out;    
15 }

booksale.hpp

 1 #pragma once
 2 #include<string>
 3 #include"book.hpp"
 4 class BookSale
 5 {
 6   public:
 7       BookSale(const Book &rb_,double sales_price_,int sales_amount_);
 8       int get_amount() const;
 9       double get_revenue() const;
10       friend std::ostream& operator<<(std::ostream &out,const BookSale &item);
11   private:
12       Book rb;
13       double sales_price;
14       int sales_amount;                 
15 };

booksale.cpp

 1 #include<iomanip>
 2 #include<iostream>
 3 #include<string>
 4 #include"booksale.hpp"
 5  BookSale::BookSale(const Book &rb_,double sales_price_,int sales_amount_):rb{rb_},sales_price{sales_price_},sales_amount{sales_amount_} 
 6  {
 7  }
 8  int BookSale::get_amount() const
 9  {
10      return sales_amount;
11   } 
12  double BookSale::get_revenue() const
13  {
14      return  sales_amount * sales_price;
15   }
16  std::ostream& operator<<(std::ostream &out,const BookSale &item)
17  {
18      using std::left;
19      using std::setw;
20      out<<left;
21      out<<item.rb<<'\n' << setw(15) << "售价:" << item.sales_price << '\n'<< setw(15) << "销售数量:" << item.sales_amount << '\n'<< setw(15) << "营收:" << item.get_revenue();
22     return out;
23  }

task2.cpp

 1 #include"booksale.hpp"
 2 #include<iostream> 
 3 #include<string>
 4 #include<vector>
 5 #include<algorithm>
 6  bool compare_by_amount(const BookSale &x1,const BookSale &x2)
 7  {
 8      return x1.get_amount() >x2.get_amount() ;
 9  }
10  void test()
11  {
12      using namespace std;
13      vector<BookSale> sales_lst;
14      int books_number;
15      cout<<"录入图书数量:";
16      cin>>books_number;
17      cout<<"录入图书数量"<<endl;
18      for(int i=0;i<books_number;++i)
19      {
20          string name,author,translator,isbn;
21          float price;
22          cout<<string(20,'-')<<""<<i+1<<"本图书信息录入"<<string(20,'-')<<endl;
23         cout << "录入书名: ";
24         cin >> name;
25         cout << "录入作者: ";
26         cin >> author;
27         cout << "录入译者: ";
28         cin >> translator;
29         cout << "录入isbn: ";
30         cin >> isbn;
31         cout << "录入定价: ";
32         cin >> price;
33         Book book(name,author,translator,isbn,price);
34         float sales_price;
35         int sales_amount;
36         cout << "录入售价: ";
37         cin >> sales_price;
38         cout << "录入销售数量: ";
39         cin >> sales_amount;
40         BookSale record(book,sales_price,sales_amount);
41         sales_lst.push_back(record); 
42     }
43     sort(sales_lst.begin(),sales_lst.end(),compare_by_amount);
44     cout<<string(20,'=')<<"图书销售统计"<<string(20,'=')<<endl;
45     for(auto &t:sales_lst)
46     {
47         cout<<t<<endl;
48         cout<<string(40,'-')<<endl; 
49     }
50 }
51  int main()
52  {
53      test();
54  }

运行结果截图

实验2.2

问题1:重载运算符<<
(1)找出<<被重载了几处?用于哪些类型?
答:2处。Book类和BookSale类
(2)找出使用重载<<输出对象的代码,写在下面。
答: std::ostream& operator<<(std::ostream &out,const BookSale &item)
    {
     using std::left;
     using std::setw;
      out<<left;
     out<<item.rb<<'\n' << setw(15) << "售价:" << item.sales_price << '\n'<< setw(15) << "销售数量:" << item.sales_amount << '\n'<< setw(15) << "营收:" << item.get_revenue();
     return out;
}
for(auto &t:sales_lst)
{
cout<<t<<endl;
cout<<string(40,'-')<<endl;
}
问题2:图书销售统计
(1)"按销售数量降序排序",描述降序排序实现方式。
答:用了sort()函数和 bool compare_by_amount(const BookSale &x1,const BookSale &x2),sort()实现的排序方式是由compare_by_amount来规定的。
(2)拓展(选答*):如果使用lambda表达式,如何实现?
答: sort(sales_lst.begin(), sales_lst.end(), [](const BookSale &x1, const BookSale &x2) {return x1.get_amount() > x2.get_amount();});

任务三

taask3_1.cpp

 1 #include<iostream>
 2  class A
 3  {
 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   }
13  void A::display() const
14 {
15     std::cout<<x<<", "<<y<<'\n'; 
16  } 
17  class B
18  {
19      public:
20          B(double x0,double y0);
21          void display() const;
22      private:
23         double x,y;    
24  };
25  B::B(double x0,double y0):x{x0},y{y0}
26  {
27   } 
28   void B::display() const
29   {
30       std::cout<<x<<", "<<y<<'\n'; 
31    } 
32   void test()
33   {
34       std::cout<<"测试类A:"<<'\n';
35     A a(3,4);
36     a.display();
37     std::cout<<"\n测试类B: "<<'\n';
38     B b(3.2,5.6);
39     b.display();     
40    }
41    int main()
42    {
43        test();
44     } 

task3_2.cpp

 1 #include<iostream>
 2 #include<string>
 3  template<typename T> 
 4  class X
 5  {
 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  }
16  template<typename T>
17  void X<T>::display() 
18  {
19   std::cout << x << ", " << y << '\n';
20 }
21  void test()
22  {
23      std::cout << "测试1: 用int实例化类模板X" << '\n';
24     X<int> x1(3, 4);
25     x1.display();
26     std::cout << "\n测试2: 用double实例化类模板X" << '\n';
27     X<double> x2(3.2, 5.6);
28     x2.display();  
29     std::cout << "\n测试3: 用string实例化类模板X" << '\n';
30     X<std::string> x3("hello", "oop");
31     x3.display();
32  }
33  int main()
34  {
35      test();
36  }

运行结果截图

1

屏幕截图 2025-12-15 172700

任务四

pet.hpp

 1 #pragma once
 2 #include<iostream>
 3  class MachinePet
 4  {
 5   public:
 6        MachinePet(std::string nickname_):nickname{nickname_}
 7        {
 8        }
 9      std::string get_nickname() const 
10     {
11               return nickname;
12        }
13      virtual std::string talk() const=0;  
14   private:
15      std::string nickname;    
16 };
17  class PetCat:public MachinePet
18  {
19      public:
20          PetCat(std::string nickname_):MachinePet(nickname_)
21         {
22         }
23          std::string talk() const override
24          {
25              return"miao wu~";
26          }
27     private:
28        std::string nickname;     
29  };
30  class PetDog:public MachinePet
31  {
32      public:
33          PetDog(std::string nickname_):MachinePet(nickname_)
34          {
35          }
36         std::string talk() const override
37          {
38                  return"wang wang~";
39          }
40     private:
41         std::string nickname;
42  };

task4.cpp

 1 #include<iostream>
 2 #include<memory>
 3 #include<vector>
 4 #include"pet.hpp"
 5 void test1()
 6 {
 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   {
12       std::cout<<ptr->get_nickname()<<" says "<<ptr->talk()<<'\n';
13       delete ptr;
14       }    
15 }
16 void test2() 
17 {
18 
19  std::vector<std::unique_ptr<MachinePet>> pets;
20  pets.push_back(std::make_unique<PetCat>("miku"));
21  pets.push_back(std::make_unique<PetDog>("da huang"));
22  for(auto const &ptr: pets)
23    std::cout << ptr->get_nickname() << " says " << ptr->talk() << '\n';
24 }
25  void test3()
26 {
27  const PetCat cat("miku");
28  std::cout << cat.get_nickname() << " says " << cat.talk() <<'\n';
29  const PetDog dog("da huang");
30  std::cout << dog.get_nickname() << " says " << dog.talk() << '\n';
31  }
32  int main() 
33 {
34  std::cout << "测试1: 使用原始指针\n";
35  test1();
36  std::cout << "\n测试2: 使用智能指针\n";
37  test2();
38  std::cout << "\n测试3: 直接使用类\n";
39  test3();
40  }

运行结果截图

实验4

任务五

Complex.hpp

 1 #pragma once
 2 #include <iostream>
 3 #include<string>
 4 template<typename T>
 5 class Complex
 6 {
 7   public:
 8       Complex():real{0},imag{0}
 9       {
10           
11       }
12     Complex(T real_,T imag_):real{real_},imag{imag_}
13     {       
14        }
15     
16     Complex(const Complex<T>& other)
17     {
18        imag=other.imag;
19        real=other.real;
20            }       
21     T get_real() const
22     {
23            return real;
24        }
25     T get_imag() const
26     {
27         return imag;
28     }
29     Complex<T>& operator+=(const Complex<T>& other) 
30      {
31         real +=other.real;
32          imag +=other.imag;
33         return *this; 
34     }
35     friend Complex<T> operator+(const Complex<T> &c1,const Complex<T> &c2)
36     {
37         return  Complex<T>(c1.real+c2.real,c1.imag+c2.imag);
38     }
39      friend bool operator==(const Complex<T> &c1,const Complex<T> &c2)
40      {
41          return  (c1.real==c2.real)&&(c2.imag==c1.imag);
42      }
43      friend std::istream& operator>>(std::istream& in,Complex<T> &c)
44      {
45          in>>c.real >>c.imag ;
46       } 
47      friend std::ostream& operator<<(std::ostream& out,const Complex<T> &c)
48      {
49          if(c.imag>=0)
50          out<<c.real <<" + "<<c.imag<<'i';
51         else
52          out<<c.real <<" - "<<-c.imag <<'i';  
53         return out; 
54       } 
55   private:
56       T imag,real;
57 };

task5.cpp

#include <iostream>
 #include "Complex.hpp"
 void test1() 
 {
  using std::cout;
  using std::boolalpha;
  Complex<int> c1(2, -5), c2(c1);
  cout << "c1 = " << c1 << '\n';
  cout << "c2 = " << c2 << '\n';
  cout << "c1 + c2 = " << c1 + c2 << '\n';
  c1 += c2;
  cout << "c1 = " << c1 << '\n';
  cout << boolalpha << (c1 == c2) << '\n';
 }
 void test2() 
 {
  using std::cin;
  using std::cout;
  Complex<double> c1, c2;
  cout << "Enter c1 and c2: ";
  cin >> c1 >> c2;
  cout << "c1 = " << c1 << '\n';
  cout << "c2 = " << c2 << '\n';
  const Complex<double> c3(c1);
  cout << "c3.real = " << c3.get_real() << '\n';
  cout << "c3.imag = " << c3.get_imag() << '\n';
 }
 int main()  
 {
  std::cout << "自定义类模板Complex测试1: \n";
  test1();
  std::cout << "\n自定义类模板Complex测试2: \n";
  test2();
 }

运行结果截图

实验5

 总结与体会

 本次实验深入理解了多态继承和模板类的运用,尤其是模板类中构造函数,成员函数的用法,如构造函数中不单单是Complex &other就可以解决的,而是Complex<T> &other,这是之前的盲区,并对运算符重载有了新的认识,可以让一些运算符变得更加直观,输出更加简易。

posted @ 2025-12-15 17:29  零和星际  阅读(2)  评论(0)    收藏  举报