c++繼承方式
派生類繼承了基類中除了構造和析構函數外所有部分,並且基類成員在子類中訪問屬性取決於繼承方式。c++類中的成員函數和變量有三種繼承方式,分別為:公有繼承(public),私有繼承(private)和保護繼承(protect)。
public:用該關鍵字修飾的成員表示公有成員,該成員不僅可以在類內可以被訪問,在類外也是可以被訪問的,是類對外提供的可訪問接口;
private:用該關鍵字修飾的成員表示私有成員,該成員僅在類內可以被訪問,在類體外是隱藏狀態;
protected:用該關鍵字修飾的成員表示保護成員,保護成員在類體外同樣是隱藏狀態,但是對於該類的派生類來說,相當於公有成員,在派生類中可以被訪問。
一、公有繼承(public)
公有繼承時,基類的公有成員和保護成員在派生類中屬性不變,但私有成員不可直接訪問。基類成員對派生類對象的可見性為:基類的公有成員可見,保護成員和私有成員不可見,即通過派生類的對象只能訪問基類的public成員。
所以,在公有繼承時,派生類的對象可以直接訪問基類中的公有成員,派生類的成員函數可以直接訪問基類中的公有成員和保護成員。
#include<iostream>
using namespace std;
class point{
private: int x, y;
public:
void initpoint(float x1 = 0, float y1 = 0) {
x = x1;
y = y1;
}
void move(float xx=0, float yy=0) {
x += xx;
y += yy;
}
float getx() const{
return x;
}
float gety() const {
return y;
}
};
class Rectangle :public point { //公有繼承
private:
int w, h;
public:
void initRectangle(float x, float y, float w, float h) {
initpoint(x, y);
this->w = w;
this->h = h;
}
float geth() const {
return h;
}
float getw() const {
return w;
}
};
int main() {
Rectangle rect;
rect.initRectangle(2, 3, 20, 30);
rect.move(3, 2);
cout << rect.getx() << endl;
cout << rect.gety() << endl;
cout << rect.getw() << endl;
cout << rect.geth() << endl;
return 0;
}
我們可以看出,在初始化時,由於不能直接初始化基類私有成員,我們直接調用了initpoint這個函數接口。這個函數是基類中的,由於是public方式直接可以使用此基類成員函數。
一、私有繼承(public)
當繼承方式為私有繼承時,基類的公有成員和保護成員都以私有成員出現在派生類中,同樣私有成員在派生類中不可直接訪問。此時派生類成員函數可以調用基類公有成員和保護成員,但是在類外部不可使用任何基類成員。可以看出,再進一步派生的話,基類所有成員就無法被直接訪問。一般私有繼承的使用比較少。
#include<iostream>
using namespace std;
class point {
private: int x, y;
public:
void initpoint(float x1 = 0, float y1 = 0) {
x = x1;
y = y1;
}
void move(float xx = 0, float yy = 0) {
x += xx;
y += yy;
}
float getx() const {
return x;
}
float gety() const {
return y;
}
};
class Rectangle :private point { //私有繼承
private:
int w, h;
public:
void initRectangle(float x, float y, float w, float h) {
initpoint(x, y);
this->w = w;
this->h = h;
}
float getx() const {
return point::getx();
}
float gety() const {
return point::gety();
}
float geth() const {
return h;
}
float getw() const {
return w;
}
void move(float offx, float offy) {
point::move(offx, offy);
}
};
int main() {
Rectangle rect;
rect.initRectangle(2, 3, 20, 30);
rect.move(1, 1);
cout << rect.getx() << endl;
cout << rect.gety() << endl;
cout << rect.getw() << endl;
cout << rect.geth() << endl;
return 0;
}
需要注意的是,私有繼承后基類成員函數只能在派生類函數中使用,在外部引用會報錯。如派生類直接調用move函數時就會報錯。為了保證派生類繼續擁有基類的接口,就需要重新聲明相同的成員例如上例重新聲明了getx(),gety(),和move()函數,根據基類隱藏原則基類函數被隱藏,但實現的是相同的效果。
三.保護繼承
在保護繼承中,基類公有成員和保護成員都以保護成員出現在派生類中,但基類私有成員仍然不能被直接訪問。保護在派生類中被視為公有成員,在類外被視為私有成員。他結合了公有成員和私有成員的優點,更合理地保護成員。私有繼承和保護繼承的區別中。所有成員的訪問屬性都完全相同,但是如果派生類繼續派生,保護繼承下的基類成員一直都存在派生類基類中,但是私有成員將無法訪問基類成員。
保護繼承既實現成員隱蔽,又方便繼承。
來看一個錯誤例子。
#include<iostream>
using namespace std;
class A {
protected:
int x;
};
int main() {
A a;
a.x = 1;
return 0;
}
我們看出他會報錯。
在沒有派生類的情況下,保護類型和私有類型相似,他們都不能在類外訪問,否則會報錯。但是如果A類以公有派生產生了B類,則在B類中,A中的保護成員像公有成員一樣可以直接調用。
#include<iostream>
using namespace std;
class A {
protected:
int x;
};
class B:public A{
public:
void fuc(){
x = 5;
cout << x;
}
};
int main() {
B b;
b.fuc();
return 0;
}
需要注意的是,如果B是A的派生,B中的成員函數只能通過B的對象訪問A中定義的protected成員,而不能通過A的對象訪問A中的protected成員。
三中繼承方式總結為下圖: