C++中 public和private派生類繼承問題和訪問權限問題

 

當一個子類從父類繼承時,父類的所有成員成爲子類的成員,此時對父類成員的訪問狀態由繼承時使用的繼承限定符決定。
1.如果子類從父類繼承時使用的繼承限定符是public,那麼
(1)父類的public成員成爲子類的public成員,允許類以外的代碼訪問這些成員
(2)父類的private成員仍舊是父類的private成員,子類成員不可以訪問這些成員;
(3)父類的protected成員成爲子類的protected成員,只允許子類成員訪問;
2.如果子類從父類繼承時使用的繼承限定符是private,那麼
(1)父類的public成員成爲子類的private成員,只允許子類成員訪問
(2)父類的private成員仍舊是父類的private成員,子類成員不可以訪問這些成員;
(3)父類的protected成員成爲子類的private成員,只允許子類成員訪問;
3.如果子類從父類繼承時使用的繼承限定符是protected,那麼
(1)父類的public成員成爲子類的protected成員,只允許子類成員訪問
(2)父類的private成員仍舊是父類的private成員,子類成員不可以訪問這些成員;
(3)父類的public成員成爲子類的protected成員,只允許子類成員訪問;

至於類中不同成員(public、private和protected)的訪問狀態就不細說了。

 

c++訪問權限和派生繼承

在基類中,public表示成員是公有的:可以由程序中任何函數訪問。所以公有成員一般是成員函數,它提供了外部程序與類的接口功能,用戶通過公有成員訪問該類對象中的數據。

private表示成員是私有的,只允許本類的成員函數和類的友元函數訪問,任何外部程序對它訪問都是非法的,所有它往往是用來描述該類對象屬性的一些數據成員,是類中被隱藏的部分。

protect表示成員是受保護類型的,與私有成員在一般情況下含義相同,它們的區別是,在類的繼承中對產生的新類影響不同。

第一:private, public, protected 訪問標號的訪問範圍。
private:只能由1.該類中的函數、2.其友元函數訪問。
不能被任何其他訪問,該類的對象也不能訪問。

protected:可以被1.該類中的函數、2.其友元函數訪問 3.子類的函數。
但不能被該類的對象訪問。

public:可以被1.該類中的函數、2.其友元函數訪問 3.子類的函數、也可以由4.該類的對象訪問。
只有公有成員才能在類的外部訪問。如
class A
{
private:
int a;
public:
int b;
protected:
int c;
};
A ca;
ca.a //error
ca.b // ok
ca.c //error

class B :public A
{
public:
int d;
}

B cb;
cb.b; //ok
cb.c //error。雖然c也是B的成員,但c在被繼承的時候變成私有或者受保護的成員了。

注:友元函數包括3種:設爲友元的普通的非成員函數;設爲友元的其他類的成員函數;設爲友元類中的所有成員函數。

派生類的生成過程:

class employee

{

protect:

char *name; //姓名

int individualEmpNo; //個人編號

int grade; //級別

float accumPay; //月薪總額

static int employeeNo; //本公司職員編號目前最大值

public:

employee();

~employee();

void pay(); //計算月薪函數

void promote(int); //升級函數

void displayStatus(); //顯示人員信息

};

class technician:public employee

{

private:

float hourlyRate; //每小時酬金

int workHours; //當月工作時數

public:

technician(); //構造函數

void pay(); //計算月薪函數

void displayStatus(); //顯示人員信息

};

分析派生新類這個過程,其繼承和派生機制的主要目的是實現代碼的重用和擴充。實際是經歷了三個步驟:吸收基類成員、改造基類成員、添加新的成員。

1.吸收基類成員

第一步是將基類的成員全盤接收:包含了它的所有基類中除構造和析構函數之外的所有成員。

這裏派生類technician繼承了基類employee的除構造和析構函數以外的所有成員:

name; individualEmpNo; grade; accumPay; employeeNo;

pay(); promote(int); displayStatus();

經過派生過程,這些成員便存在於派生類之中。

2.改造基類函數

對基類成員的改造包括兩個方面,

一個是基類成員的訪問控制問題,主要依靠派生類聲明時的繼承方式來控制:

類的繼承方式:public、protected和private三種訪問屬性。 (見上)

第二個是對基類數據或函數成員的覆蓋,

如果派生類聲明瞭一個和某個基類成員同名的新成員(如果是成員函數,則參數表也要相同,

如pay(); displayStatus(); 參數不同的情況屬於重載)派生的新成員就覆蓋了外層同名函數。這時,在派生類中或者通過派生類的對象直接使用成員名就只能訪問到派生類中聲明的同名成員,這稱爲同名覆蓋。

3.添加新的成員

我們可以根據實際情況的需要,給派生類添加適當的數據和函數成員,來實現必要的新增功能。如technician派生類中的hourlyRate和workHours,在派生過程中,由於基類的構造函數和析構函數是不能被繼承下來的,因此我們就需要在派生類重新加入新的構造函數和析構函數來實現一些特別的初始化和清理工作,例如派生類technician的構造函數technician();


第二:類的繼承後方法屬性變化。
特別的private,它們與派生類中新增加的private成員不同,派生類函數或是建立派生類對象的模塊都無法訪問到它們。)(所以只能通過在派生類中調用基類的函數去訪問private屬性,也可以把基類的函數用public繼承下來來訪問)
private繼承,父類的所有方法在子類中變爲private;
protected繼承,父類的protected和public方法在子類中變爲protected,private方法不變;
public繼承,父類中的方法屬性不發生改變; 原來是怎樣就怎樣
public一般爲函數和數據,protected和private一般只爲數據。
public和protected在任何方式繼承的情況下,也能被子類函數調用。
如下所示:
public: protected: private:
public繼承 public(含繼承下來的基類函數) protected 特別的private(用派生類對象訪問時)可以
被public繼承下來的基類函數直接調用
protected繼承 protected protected 特別的private
protected :不能被派生類對象直接調用,可間接被派生類函數和基類函數調用
特別的private:不能被派生類函數和派生類對象直接調用,(用派生類對象訪問時)只能重新定義:調用基類 因爲private不能被子類函數訪問
private繼承 private private 特別的private
private:不能被派生類對象直接調用,1.可間接被派生類函數重新定義來調用。2.基類函數調用(用派生類對象訪問時)只能重新定義:調用基類 因爲public和protected能被子類函數訪問
上面爲一次繼承的情況,若有些是沒區別的,當時如果再繼承的話就有區別了
繼承下來的訪問屬性分爲四種:
1.區分繼承與訪問,特別的private爲不能繼承下來的,但可以訪問
2.(private)成員:包括從基類繼承下來的非私有成員(私有繼承時),以及派生類中新增加的私有成員,在派生類內部函數都可以訪問到,但派生類對象不能訪問。
3.(protected)可能是新增也可能是從基類繼承過來的,派生類內部成員函數可以訪問,當派生類對象無法訪問。
4.(public)成員:派生類成員函數和對象都能訪問到

protected繼承和private繼承能降低訪問權限。
當類的繼承方式爲public時,
基類的public和protected成員的訪問屬性在派生類中不變,而基類的private成員仍保持私有屬性。
可得:派生類的其他成員函數和對象可以直接訪問基類的公有成員和保護成員。
無論是派生類的成員,還是派生類的對象都無法訪問基類的私有成員。
其他外部使用者只能通過派生類的對象訪問繼承來的公有成員
公有public繼承 特別性舉例:
class vehicle
{
private:
int wheels;
protected:
float weight;
public:
vehicle(int in_wheels, float in_weight)
{ wheels=in_wheels;
weight=in_weight;
}
int get_wheels(){return wheels;}
float get_weight(){return weight;}
};
class car:public vehicle
{
private:
int passenger_load;
public:
car(int in_wheels,float in_weight,int people=5):vehicle(in_wheels,in_weight)
//這裏不是調用基類構造函數,而是初始化賦值列表。
passenger_load=people;}
int get_passengers(){return passenger_load;}
};
void main()
{
car bluebird(4,1000);
cout<<"The message of bluebird(wheels,weight,passengers):"<<endl;
cout<<bluebird.get_wheels()<<","
<<bluebird.get_weight()<<","
<<bluebird.get_passengers()<<endl;
}
car public繼承verhicle後,
private:wheels;
passenger_load;// 新增的
protected:weight;
public: vehicle不存在(派生類不繼承基類的構造和析構函數)
get_wheels() //可以直接訪問
get_weight() //可以直接訪問
car
get_passengers ;
保護protected繼承
基類的public和protected成員都變爲保護成員,而基類的private成員不可訪問。
即基類中的保護成員只能被基類的成員函數或派生類的成員函數訪問。
舉例:
car protected繼承verhicle後,
private:wheels;
passenger_load;// 新增的
protected:weight;
vehicle不存在(派生類不繼承基類的構造和析構函數)
get_wheels()
get_weight()
public car
get_passengers ;
因爲get_wheels() 和 get_weight()被派生爲protected,其只能被被1.該類中的函數、2.其友元函數訪問 3.子類的函數。但不能被該類的對象訪問。
所以要在派生類中使用對象訪問,必須做一下修改:
class car:protected vehicle
{
private:
int passenger_load;
public:
car(int in_wheels,float in_weight,int people=5):vehicle(in_wheels,in_weight)
//這裏不是調用基類構造函數,而是初始化賦值列表。
passenger_load=people;}
int get_wheels (){return vehicle::get_wheels();} //重新定義get_wheels ()
float get_weight(){return weight;} //重新定義get_weight()
int get_passengers(){return passenger_load;}
};
這裏爲了保證基類的部分外部接口特徵能夠在派生類中也存在,就必須在派生類中重新定義同名的成員函數 get_wheels()和get_weight(),根據同名覆蓋的原則,在主函數中自然調用的是派生類的函數。

如果使用私有繼承: 在該例子和protected一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章