實驗6:類的繼承和多態
南京信息工程大學實驗報告
實驗名稱 類的繼承和多態 實驗日期 2018-5-29 得分 指導教師 耿學華 系 計軟院 專業 計嵌+軟嵌 年級 2017 級 班次 (1) 姓名 施昊陽 學號 20161334026
一、實驗目的
- 理解類的繼承和派生機制
- 掌握派生類的定義和使用
- 掌握派生類成員的標識與訪問中同名覆蓋原則、二元作用域分辨符和虛基類的用法
- 掌握派生類構造函數和析構函數的定義及調用次序
- 理解運算符重載的目的,掌握運算符重載函數的編寫方法
二、實驗準備
- 類的繼承和派生
請結合第 7 章課件和教材復習以下內容:- 引入繼承和派生機制的目的
- 基本概念:繼承、派生、基類、直接基類、間接基類、派生類
- 語法:
- 派生類定義的語法格式(單重繼承、多重繼承);
- 派生類構造函數極其初始化列表寫法
- 派生類成員的標識與訪問
- 同名覆蓋指的是什麽?
- 二元作用域分辨符在什麽情況下使用?
- 什麽是虛基類?引入虛基類的目的是什麽?如何使用?
- 運算符重載
請結合第 8 章課件和教材學習以下內容:- 運算符重載的目的
- 運算符重載的規則和限制
- 運算符重載函數的語法格式
- 運算符重載時,究竟重載為類的成員函數,還是友元,還是普通函數,需要綜合考慮哪些因素?
三、實驗內容
某計算機硬件系統,為了實現特定的功能,在某個子模塊設計了 ABC 三款芯片用於
數字計算。各個芯片的計算功能如下:
A 芯片:計算兩位整數的加法(m+n)、計算兩位整數的減法(m-n)
C 芯片:計算兩位整數的加法(m+n)、計算兩位整數的除法(m/n)
為 ABC 三個芯片分別定義類,描述上述芯片的功能,並在 main 函數中測試這三個類。
(提示:利用類的繼承和派生,抽象出共有屬性和操作作為基類。)定義一個車(vehicle)基類,具有數據成員 maxspeed, weight(均為 int 型), 函數成員 run(), stop(),由此派生出自行車(bicycle)類、汽車(motorcar)類。其中, bicycle 類新增數據成員高度(height),motorcar 類新增數據成員座位數(seatnum)屬性。再從 bicycle 和 motorcar 派生出摩托車(motorcycle)類,並在主程序中測試這個類。(每個類都要求定義構造函數和析構函數)
- 基於「實驗 4 類和對象-2」中設計並實現的類 Fraction,創建派生類 iFraction,用以
描述如下形式的分數:
\(1\frac 2 3\)
要求:- 更新 Fraction 類
為 Fraction 類編寫運算符+、-、、/重載函數,實現在 main 函數中直接用+、-、、/進行 Fraction 類運算。 - 設計並實現派生 iFraction 類
- 為派生類 iFraction 定義構造函數,實現 iFraction 對象的初始化
- 為派生類 iFraction 增加一個成員函數,用於在屏幕上顯示 iFraction 對象
- 設計一個普通函數 convertF()用於對 iFraction 類對象進行規範化處理。(選做)
(提示:把 convertF()設計為 Fraction 類和 iFraction 類的友元函數)
例如:(更多情形請自行考慮)
\(\frac 5 3 \to 1 \frac 2 3\)
- 更新 Fraction 類
- 以多文件結構方式編寫(fraction.h, fraction.cpp, ifraction.h, ifraction.cpp, main.cpp)
(選做)
基於提供的程序文件,補足並擴充程序,實現一個多類型玩家角色扮演遊戲。
在本次實驗附件包 ex4 中有如下文件:
container.h, container.cpp, player.h, player.cpp, swordsman.h, swordsman.cpp, main.cpp- 閱讀源碼,理解並補足程序,讓程序運行生效。
其中,程序中出現有????????之處,是需要補足的部分。 - 畫出這個角色扮演遊戲 UML 類圖,尤其是類和類之間的關系
- 設計並實現 archer 類和 mage 類。在 UML 類圖中也加進這兩個新類。
- 修改 main 函數,隨機生成不同角色的敵人,並保證程序正常運行。
- 為遊戲增加其它元素,完善遊戲的可玩性、趣味性,等。
(說明:這道涉及虛函數、運行時多態。你可以在第 8 章學完後嘗試編寫,或者,在嘗試編寫這道題的過程中,學習第 8 章虛函數和運行時多態的知識。)
- 閱讀源碼,理解並補足程序,讓程序運行生效。
四、實驗結論
- 實驗內容 1
LM51.h
#include<bits/stdc++.h> using namespace std; #ifndef _LM51_H #define _LM51_H class LM51{ protected: int m,n; public: int plus(); LM51(int M=2016,int N=133); ~LM51(); }; #endif
LM51.cpp
#include"LM51.h" int LM51::plus() { cout << "LM51.plus " << endl; return m+n; } LM51::LM51(int M,int N) { cout << "Constru }ctor LM51 is called" << endl; m=M; n=N; LM51::~LM51() { cout << "Deconstructor LM51 is called" << endl; }
A.h
#include"LM51.h" #ifndef _A_h #define _A_h class A:public LM51{ public : A(int M=2016,int N=133); int minus(); ~A(); }; #endif
A.cpp
#include"A.h" A::A(int M,int N){ m=M; n=N; cout << "Constructor A is called" << endl; } int A::minus() { cout << "A.minus " << endl; return m-n; } A::~A() { cout << "Deconstructor A is called" << endl; }
B.h
#include"LM51.h" #ifndef _B_h #define _B class B:public LM51{ public : B(int M=2016,int N=133); int mulip(); ~B(); }; #endif
B.cpp
#include"B.h" B::B(int M,int N){ m=M; n=N; cout << "Constructor B is called" << endl; } int B::mulip() { cout << "B.mulip " << endl; return m*n; } B::~B() { cout << "Deconstructor B is called" << endl; }
C.h
#include"LM51.h" #ifndef _C_h #define _C class C:public LM51{ public : C(int M=2016,int N=133); double divi(); ~C(); }; #endif
C.cpp
#include"C.h" C::C(int M,int N){ m=M; n=N; cout << "Constructor C is called" << endl; } double C::divi() { cout << "C.divi " << endl; return m/n; } C::~C() { cout << "Deconstructor C is called" << endl; }
Main.cpp
#include<bits/stdc++.h> #include "A.h" #include "B.h" #include "C.h" using namespace std; int main(){ A a(20,16); cout<<a.plus()<<endl; cout<<a.minus()<<endl; B b(13,1); cout<<b.plus()<<endl; cout<<b.mulip()<<endl; C c(40,26); cout<<c.plus()<<endl; cout<<c.divi()<<endl; return 0; }
Screenshot:
- 實驗內容 2
vehicle.h
#ifndef _VEHICLE #define _VEHICLE class vehicle{ protected: int maxspeed,weight; public: void run(); void stop(); vehicle(int M=100,int W=1000); ~vehicle(); }; #endif
vehicle.cpp
#include "vehicle.h" void vehicle::run() { cout<<"run"<<endl; } void vehicle::stop() { cout<<"stop"<<endl; } vehicle::vehicle(int M,int W) { maxspeed=M; weight=W; cout<<"Constructor vehicle is called"<<endl; } vehicle::~vehicle() { cout<<"Deconstructor vehicle is called"<<endl; }
bicycle.h
#ifndef _BICYCLE #define _BICYCLE class bicycle:virtual public vehicle{ protected: int height; public: bicycle(int M=100,int W=1000,int H=2):vehicle(M,W); ~bicycle(); }; #endif
bicycle.cpp
#include"bicycle.h" bicycle::bicycle(int M,int W,int H):vehicle(M,W) { height=H; cout<<"Constructor bicycle is called"<<endl; } bicycle::~bicycle() { cout<<"Deconstructor bicycle is called"<<endl; }
motorcar.h
#ifndef _MOTORCAR #define _MOTORCAR class motorcar:virtual public vehicle{ protected: int seatnum; public: motorcar(int M,int W,int H):vehicle(M,W); ~motorcar(); }; #endif
motorcar.cpp
#include"motocar.h" motocar::motorcar(int M,int W,int S):vehicle(M,W) { seatnum=S; cout<<"Constructor motorcar is called"<<endl; } motocar::~motorcar() { cout<<"Deconstructor motorcar is called"<<endl; }
motorcycle.h
#ifndef _MOTORCYCLE #define _MOTORCYCLE class motorcycle:public bicycle,public motorca{ public: motorcycle(int M=100,int W=1000,int S=4,int H=2):vehicle(M,W); ~motorcycle(); }; #endif
motorcycle.cpp
#include"motorcycle.h" motorcycle::motorcycle(int M,int W,int S,int H):vehicle(M,W) { seatnum=S; height=H; cout<<"Constructor motorcycle is called"<<endl; } motorcycle::~motorcycle() { cout<<"Deconstructor motorcycle is called"<<endl; }
Main.cpp
#include"vehicle.h" #include"bicycle.h" #include"motorcar.h" #include"motorcycle.h" int main(){ vehicle a; a.run(); a.stop(); bicycle b; b.run(); b.stop(); motorcar c; c.run(); c.stop(); motorcycle d; d.run(); d.stop(); return 0; }
-Screenshot:
- 實驗內容 3
iFraction.h
#include "Fraction.h" #ifndef _IFRACTION #define _IFRACTION class iFraction:public Fraction{ private: int i; public: iFraction(int t=0,int b=1,int I=0):Fraction(t,b){i=I;} iFraction(const iFraction &c0):Fraction(c0){i=c0.i;} void print(); friend iFraction convertF(const iFraction &c0); }; #endif
iFraction.cpp
#include"iFraction.h" void iFraction::print() { if(top==0){cout<<i<<endl; return ; } cout<<setw(4)<<setfill(' ')<<top<<endl; cout<<setw(3)<<setfill(' ')<<i<<'-'<<endl; cout<<setw(4)<<setfill(' ')<<bottom<<endl; } iFraction convertF(const iFraction &c0) { iFraction tmp(c0); tmp.simplify(); int tt=tmp.top/tmp.bottom; tmp.i+=tt; tmp.top%=tmp.bottom; return tmp; }
Fraction.h
#include<iostream> #include<cmath> #include <iomanip> #ifndef _FRACTION #define _FRACTION using namespace std; class Fraction { protected: int top, bottom; int gcd(int a, int b); public: Fraction(int t, int b); Fraction(int t); Fraction(); void simplify(); void add(Fraction c0); void subtract(Fraction c0); void multiple(Fraction c0); void divde(Fraction c0); bool compare(Fraction c0); void readln(); void writeln(); double todecimal(); friend Fraction operator +(const Fraction &c0,const Fraction &c1); friend Fraction operator -(const Fraction &c0,const Fraction &c1); friend Fraction operator *(const Fraction &c0,const Fraction &c1); friend Fraction operator /(const Fraction &c0,const Fraction &c1); Fraction &operator +=(const Fraction &c0) { bottom = bottom * c0.bottom; top = top * c0.bottom + c0.top * bottom; simplify(); return *this; } Fraction &operator -=(const Fraction &c0) { bottom = bottom * c0.bottom; top = top * c0.bottom - c0.top * bottom; if(bottom < 0) { top = - top; bottom = - bottom; } simplify(); return *this; } Fraction &operator *=(const Fraction &c0) { top *= c0.top; bottom *= c0.bottom; simplify(); return *this; } Fraction &operator /=(const Fraction &c0) { if(c0.top == 0) { return *this; } top *= c0.bottom; bottom *= c0.top; simplify(); return *this; } }; #endif
Fraction.cpp
#include"Fraction.h" int Fraction:: gcd(int a, int b) { return a % b == 0 ? b : gcd(b, a%b); } Fraction:: Fraction(int t, int b) { top = t; bottom = b; } Fraction:: Fraction(int t) { top = t; bottom = 1; } Fraction:: Fraction() { top = 0; bottom = 1; } void Fraction:: simplify() { if(bottom < 0) { top = - top; bottom = - bottom; } int g = gcd(abs(top),abs(bottom)); top /= g; bottom /= g; } void Fraction:: add(Fraction c0) { bottom = bottom * c0.bottom; top = top * c0.bottom + c0.top * bottom; simplify(); } void Fraction:: subtract(Fraction c0) { bottom = bottom * c0.bottom; top = top * c0.bottom - c0.top * bottom; if(bottom < 0) { top = - top; bottom = - bottom; } simplify(); } void Fraction:: multiple(Fraction c0) { top *= c0.top; bottom *= c0.bottom; simplify(); } void Fraction:: divde(Fraction c0) { if(c0.top == 0) { cout << "Error: Zero can't be divided.\n"; return ; } top *= c0.bottom; bottom *= c0.top; simplify(); } bool Fraction:: compare(Fraction c0) { return top * gcd(bottom, c0.bottom) - c0.top * gcd(bottom, c0.bottom) > 0 ? true : false; } void Fraction:: readln() { cout << "Plz input the Numerator and Denominator" << endl; cin >> top; int tmp; cin >> tmp; while (tmp == 0) { cout << "Zero can't be the Denominator, plz try again!" << endl; cin >> tmp; } bottom = tmp; } void Fraction:: writeln() { if(bottom != 1) cout << top << "/" << bottom << endl; else cout << top <<endl; } double Fraction:: todecimal() { return (double)top / bottom; } Fraction operator +(const Fraction &c0,const Fraction &c1) { Fraction tmp; tmp.bottom = c0.bottom * c1.bottom; tmp.top = c1.top * c0.bottom + c0.top * c1.bottom; tmp.simplify(); return tmp; } Fraction operator -(const Fraction &c0,const Fraction &c1) { Fraction tmp; tmp.bottom = c0.bottom * c1.bottom; tmp.top = c0.top * c1.bottom - c1.top * c0.bottom; if(tmp.bottom < 0) { tmp.top = - tmp.top; tmp.bottom = - tmp.bottom; } tmp.simplify(); return tmp; } Fraction operator *(const Fraction &c0,const Fraction &c1) { Fraction tmp; tmp.top = c0.top * c1.top; tmp.bottom = c0.bottom * c1.bottom; tmp.simplify(); return tmp; } Fraction operator /(const Fraction &c0,const Fraction &c1) { Fraction tmp; if(c0.top == 0 || c1.top == 0) { return tmp; } tmp.top = c0.top * c1.bottom; tmp.bottom = c0.bottom * c1.top; tmp.simplify(); return tmp; }
Main.cpp
#include "Fraction.h" #include "iFraction.h" int main() { Fraction c1 (11,-22); Fraction c2 (4); Fraction c3 ; c1 = c1 + c2; cout << "c1 + c2 = ";c1.writeln(); c1 += c2; cout << "c1 += c2 , c1 = ";c1.writeln(); c1 = c1 - c2; cout << "c1 - c2 = ";c1.writeln(); c1 -= c2; cout << "c1 -= c2 , c1 = ";c1.writeln(); c1 = c1 * c2; cout << "c1 * c2 = ";c1.writeln(); c1 *= c2; cout << "c1 *= c2 , c1 = ";c1.writeln(); c1 = c1 / c2; cout << "c1 / c2 = ";c1.writeln(); c1 /= c2; cout << "c1 /= c2 , c1 = ";c1.writeln(); cout << "c4="<<endl; iFraction c4(4,2,-3); c4.print(); c4=convertF(c4); cout<<"c4 = convertF(c4) = "<<endl; c4.print(); return 0; }
Screenshot:
實驗內容4:
Github Address : https://github.com/shylocks/ex_6_4.git
*Press Commits Buttom to see changes.
UML :
五、實驗總結與體會
C++ 與 Java 之間關於“類的繼承與多態”一些概念的重疊:
C++ Java
虛函數 普通函數
純虛函數 抽象函數
抽象類 抽象類
虛基類 接口
(C++先輩萬物之父說)
實驗6:類的繼承和多態