接下來討論兩件事情:
- 繼承的方式: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