接下來討論兩件事情:
- 繼承的方式:public, private, protected
- base classes中的不同類型(public, private ,protected)變數可以被derived classes使用的權限
繼承的方式:public, private, protected
最常用的是public繼承,他建立了derived classes和base classes的「is-a relationship」,例如:derived classes是car,base classes是vehicle,即car "is-a" vehicle。
定義derived classes時候,程式碼這麼寫:
class Car : public Vehicle{};
base classes中的不同類型(public, private ,protected)變數可以被derived classes使用的權限
在public形式繼承中,base classes的public變數可以被derived classes使用,private則不行,pretected變數則是設計給繼承使用的,可以被derived classes使用。
在OOP概念中,希望東西一層層分離、封裝,透過給予使用介面(interface)的方式連結,而不希望使用者(這裡指derived classes)去更變內部的資料,於是,上述的public, protected變數可以直接被derived classes使用就不會是一個好的方法,最好的方式是透過private變數再使用public的set/get函式去使用變數。
透過private變數再使用public的set/get函式去使用變數,帶來兩個最明顯的好處:
- set的函式中往往會檢查輸入值是否為有效值,或是一些客製化的處理,若是繞過set/get函式去更變變數,可能導致該變數儲存了無效值
- 若是base classes改變內部的設置(程式碼),直接讀取、使用base classes的public, protected變數的方式,derived classes的程式碼也可能要跟著更變,導致整份程式變得複雜麻煩,而使用set/get的方式可以避免這樣的問題,即是「封裝」的概念
一些事情
- base classes的程式碼是不需要因為繼承而有任何更改的
- derived classes程式碼中要include base classes存放的header檔
- derived classes程式碼中要使用base classes中的變數或函式可以直接使用,但若是該變數或函式已經被另一個相同名稱的變數或函式覆蓋,可以在前面加上"base clesses name::"的方式讀取使用,例如:Vehicle::drive()
- 若是base classes已經有的東西盡量避免重複撰寫,善用base classes提供的函式
以下範例是用Student當作base class,每個Student object有自己的名字、分數,然後有一個叫做GodStudent的class當作derived class,繼承Student,GodStudent "is-a" Student,但是GodStudent與其他Student不同的是,他對於自己有一個最低標準分數(baseScore)。
base class的header (Student.h)
#include <string> using namespace std; class Student{ public: Student(const string &, int = 0); void setName(const string &); string getName() const; void setScore(int); int getScore() const; void print() const; private: string name; int score; };
base class的implementation (Student.cpp)
#include <iostream> #include <string> #include "Student.h" using namespace std; Student::Student(const string &_name, int _score){ name = _name; score = _score; } // name, set/get void Student::setName(const string &_name){ name = _name; } string Student::getName() const{ return name; } // score, set/get void Student::setScore(int _score){ score = _score; } int Student::getScore() const{ return score; } // print void Student::print() const{ cout << "Name >> " << name << "\tScore >> " << score << endl; }
derived class的header (GodStudent.h)
#include <string> #include "Student.h" using namespace std; class GodStudent : public Student{ public: GodStudent(const string &, int = 0, int = 90); void setBaseScore(int); int getBaseScore() const; void print() const; private: int baseScore; };
derived class的implementation (GodStudent.cpp)
#include <iostream> #include "GodStudent.h" using namespace std; GodStudent::GodStudent(const string &_name, int _score, int _baseScore) :Student(_name, _score){ setBaseScore(_baseScore); } void GodStudent::setBaseScore(int _baseScore){ baseScore = _baseScore; } int GodStudent::getBaseScore() const{ return baseScore; } void GodStudent::print() const{ // accessing protected variables /* cout << "Protected Variables" << endl; cout << "Name >> " << name << "\tScore >> " << score; cout << "\tBaseScore >> " << baseScore << endl; */ // accessing private variables cout << "\nPrivate Variables" << endl; Student::print(); cout << "BaseScore >> " << baseScore << endl; }
使用者的主程式 (main.cpp)
#include <iostream> #include <iomanip> #include "GodStudent.h" using namespace std; int main(){ GodStudent heron("Heron", 100, 90); cout << "getName >> " << heron.getName() << endl; cout << "getScore >> " << heron.getScore() << endl; cout << "getBaseScore >> " << heron.getBaseScore() << endl; heron.setScore(120); heron.print(); return 0; }
No comments:
Post a Comment