C++繼承的一般語法為:
class 派生類名:[繼承方式] 基類名{
派生類新增加的成員
};
繼承方式限定了基類成員在派生類中的訪問權限,包括 public(公有的)、private(私有的)和 protected(受保護的)。此項是可選項,如果不寫,默認為 private(成員變量和成員函數默認也是 private)。
現在我們知道,public、protected、private 三個關鍵字除了可以修飾類的成員,還可以指定繼承方式。
public、protected、private 修飾類的成員
類成員的訪問權限由高到低依次為 public --> protected --> private,我們在《C++類成員的訪問權限》一節中講解了 public 和 private:public 成員可以通過對象來訪問,private 成員不能通過對象訪問。
現在再來補充一下 protected。protected 成員和 private 成員類似,也不能通過對象訪問。但是當存在繼承關系時,protected 和 private 就不一樣了:基類中的 protected 成員可以在派生類中使用,而基類中的 private 成員不能在派生類中使用,下面是詳細講解。
public、protected、private 指定繼承方式
不同的繼承方式會影響基類成員在派生類中的訪問權限。
1) public繼承方式
-
基類中所有 public 成員在派生類中為 public 屬性;
-
基類中所有 protected 成員在派生類中為 protected 屬性;
-
基類中所有 private 成員在派生類中不能使用。
2) protected繼承方式
-
基類中的所有 public 成員在派生類中為 protected 屬性;
-
基類中的所有 protected 成員在派生類中為 protected 屬性;
-
基類中的所有 private 成員在派生類中不能使用。
3) private繼承方式
-
基類中的所有 public 成員在派生類中均為 private 屬性;
-
基類中的所有 protected 成員在派生類中均為 private 屬性;
-
基類中的所有 private 成員在派生類中不能使用。
通過上面的分析可以發現:
1) 基類成員在派生類中的訪問權限不得高於繼承方式中指定的權限。例如,當繼承方式為 protected 時,那麼基類成員在派生類中的訪問權限最高也為 protected,高於 protected 的會降級為 protected,但低於 protected 不會升級。再如,當繼承方式為 public 時,那麼基類成員在派生類中的訪問權限將保持不變。
也就是說,繼承方式中的 public、protected、private 是用來指明基類成員在派生類中的最高訪問權限的。
2) 不管繼承方式如何,基類中的 private 成員在派生類中始終不能使用(不能在派生類的成員函數中訪問或調用)。
3) 如果希望基類的成員能夠被派生類繼承並且毫無障礙地使用,那麼這些成員只能聲明為 public 或 protected;只有那些不希望在派生類中使用的成員才聲明為 private。
4) 如果希望基類的成員既不向外暴露(不能通過對象訪問),還能在派生類中使用,那麼只能聲明為 protected。
注意,我們這裡說的是基類的 private 成員不能在派生類中使用,並沒有說基類的 private 成員不能被繼承。實際上,基類的 private 成員是能夠被繼承的,並且(成員變量)會占用派生類對象的內存,它只是在派生類中不可見,導致無法使用罷了。private 成員的這種特性,能夠很好的對派生類隱藏基類的實現,以體現面向對象的封裝性。
下表匯總了不同繼承方式對不同屬性的成員的影響結果
繼承方式/基類成員 |
public成員 |
protected成員 |
private成員 |
public繼承 |
public
protected
不可見
protected繼承 |
protected
protected
不可見
private繼承 |
private
private
不可見
由於 private 和 protected 繼承方式會改變基類成員在派生類中的訪問權限,導致繼承關系復雜,所以實際開發中我們一般使用 public。
【示例】演示類的繼承關系。
#include<iostream>
using namespace std;
//基類People
class People{
public:
void setname(char *name);
void setage(int age);
void sethobby(char *hobby);
char *gethobby();
protected:
char *m_name;
int m_age;
private:
char *m_hobby;
};
void People::setname(char *name){ m_name = name; }
void People::setage(int age){ m_age = age; }
void People::sethobby(char *hobby){ m_hobby = hobby; }
char *People::gethobby(){ return m_hobby; }
//派生類Student
class Student: public People{
public:
void setscore(float score);
protected:
float m_score;
};
void Student::setscore(float score){ m_score = score; }
//派生類Pupil
class Pupil: public Student{
public:
void setranking(int ranking);
void display();
private:
int m_ranking;
};
void Pupil::setranking(int ranking){ m_ranking = ranking; }
void Pupil::display(){
cout<<m_name<<"的年齡是"<<m_age<<",考試成績為"<<m_score<<"分,班級排名第"<<m_ranking<<",TA喜歡"<<gethobby()<<"。"<<endl;
}
int main(){
Pupil pup;
pup.setname("小明");
pup.setage(15);
pup.setscore(92.5f);
pup.setranking(4);
pup.sethobby("乒乓球");
pup.display();
return 0;
}
運行結果:
小明的年齡是15,考試成績為92.5分,班級排名第4,TA喜歡乒乓球。
這是一個多級繼承的例子,Student 繼承自 People,Pupil 又繼承自 Student,它們的繼承關系為 People --> Student --> Pupil。Pupil 是最終的派生類,它擁有基類的 m_name、m_age、m_score、m_hobby 成員變量以及 setname()、setage()、sethobby()、gethobby()、setscore() 成員函數。
注意,在派生類 Pupil 的成員函數 display() 中,我們借助基類的 public 成員函數 gethobby() 來訪問基類的 private 成員變量 m_bobby,因為 m_hobby 是 private 屬性的,在派生類中不可見,所以只能借助基類的 public 成員函數 sethobby()、gethobby() 來訪問。
在派生類中訪問基類 private 成員的唯一方法就是借助基類的非 private 成員函數,如果基類沒有非 private 成員函數,那麼該成員在派生類中將無法訪問(除非使用下面講到的 using 關鍵字)。
改變訪問權限
使用 using 關鍵字可以改變基類成員在派生類中的訪問權限,例如將 public 改為 private、將 private 改為 public。
using 關鍵字使用示例:
#include<iostream>
using namespace std;
//基類People
class People{
public:
void show();
protected:
char *m_name;
int m_age;
};
void People::show(){
cout<<m_name<<"的年齡是"<<m_age<<endl;
}
//派生類Student
class Student: public People{
public:
void learning();
public:
using People::m_name; //將private改為public
using People::m_age; //將private改為public
float m_score;
private:
using People::show; //將public改為private
};
void Student::learning(){
cout<<"我是"<<m_name<<",今年"<<m_age<<"歲,這次考了"<<m_score<<"分!"<<endl;
}
int main(){
Student stu;
stu.m_name = "小明";
stu.m_age = 16;
stu.m_score = 99.5f;
stu.show(); //compile error
stu.learning();
return 0;
}
代碼中首先定義了基類 People,它包含兩個 protected 屬性的成員變量和一個 public 屬性的成員函數。定義 Student 類時采用 public 繼承方式,People 類中的成員在 Student 類中的訪問權限默認是不變的。
不過,我們使用 using 改變了它們的默認訪問權限,如代碼第16~20行所示,將 say() 函數修改為 private 屬性的,是降低訪問權限,將 name、age 變量修改為 public 屬性的,是提高訪問權限。
因為 say() 函數是 private 屬性的,所以代碼第33行會報錯。把該行注釋掉,程序輸出結果為:
我是小明,今年16歲,這次考了99.5分!