繼承:ios
覆蓋:函數
若派生類中定義了一個與基類中同名的成員,則會出現基類與派生類有同名成員的狀況,這是容許的。同名的成員既能夠是成員變量,也能夠是成員函數。這種狀況下,若在派生類的成員函數中訪問這個同名成員,或經過派生類對象訪問這個同名成員時,除非特別指明,訪問的就是派生類中的成員,這種狀況叫「覆蓋」,即派生類的成員覆蓋基類的同名成員。覆蓋也稱爲重定義或是重寫。對於成員函數來講,派生類既繼承了基類的同名成員函數,又在派生類中重寫了這個成員函數。這稱爲函數重定義,也稱爲同名隱藏。「隱藏」的意思是指,使用派生類對象調用這個名字的成員函數時,調用的是派生類中定義的成員函數,即隱藏了基類中的成員函數。spa
派生類能夠改變基類中成員的訪問權限
空類也能夠做爲基類,也就是說,空類能夠派生子類:設計
class emptyClass{ }; //空基類 class subemptyClass : public emptyClass{ }; //派生類
類的大小指針
一、友元code
若是基類有友元類或友元函數,則其派生類不會因繼承關係而也有此友元類或友元函數。若是基類是某類的友元,則這種友元關係是被繼承的。即被派生類繼承過來的成員函數,若是原來是某類的友元函數,那麼它做爲派生類的成員函數仍然是某類的友元函數。總之,基類的友元不必定是派生類的友元;基類的成員函數是某類的友元函數,則其做爲派生類繼承的成員函數還是某類的友元函數。對象
#include<iostream> using namespace std; class another; //前向引用聲明 //基類 class Base { private: float x; public: void print(const another &K); }; //派生類 class Derived:public Base { private: float y; }; //其餘類 class another{private: int aaa; public: another(){ aaa=100; } friend void Base::print(const another &K);//基類的成員函數聲明爲本類的友元 }; void Base::print(const another &K){ cout<<"Base:"<<K.aaa<<endl; //能夠訪問私有成員變量 } int main(){ Base a; Derived d; another ano; //aaa 初始化爲100 a.print(ano); //輸出爲:Base:100 d.print(ano); //輸出爲:Base:100 return 0; }
二、靜態屬性blog
若是基類中的成員是靜態的,則在其派生類中,被繼承的成員也是靜態的,即其靜態屬性隨靜態成員被繼承。
若是基類的靜態成員是公有的或是保護的,則它們被其派生類繼承爲派生類的靜態成員。訪問這些成員時,一般用「<類名>::<成員名>」的方式引用或調用。不管有多少個對象被建立,這些成員都只有一個拷貝,它爲基類和派生類的全部對象所共享。繼承
#include<iostream> using namespace std; // 基類 class Base { private: float x; public: static int staV; Base(){ staV++; } }; int Base::staV=0; //派生類 class Derived: public Base { private: float y; public: Derived( ){ staV++; } }; int main(){ Base a; cout<< "Base:" <<a.staV<<endl; //輸出1 Derived d; cout<< "Derived:" << d.staV<<endl; //輸出3(建立子類對象會調用父類構造器,而後調用自身的構造器) return 0; }
三、繼承之間的訪問關係內存
#include<iostream> using namespace std; class CB{ public: int a; CB(int x){ a=x; } void showa(){ cout<<"Class CB--a="<<a<<endl; } }; class CD:public CB{ public: int a; //與基類a同名 //x用來初始化基類的成員變量a CD(int x,int y):CB(x) { a=y; } //與基類showa同名 void showa() { cout<<"Class CD--a="<<a<<endl; } //訪問派生類a void print2a(){ cout<<"a=" << a<<endl; //訪問基類a cout<<"CB::a="<<CB::a<<endl; } }; int main(){ CB CBobj(12); CBobj.showa();//Class CB--a=12 CD CDobj(48,999); CDobj.showa(); //訪問派生類的showa () Class CD--a=999 CDobj.CB::showa(); //訪問基類的showa () Class CB--a=48 cout<<"CDobj.a="<<CDobj.a<<endl; // CDobj.a=999 cout<<"CDobj.CB::a="<<CDobj.CB::a<<endl;//CDobj.CB::a=48 }
四、protected訪問範圍說明符
#include<iostream> using namespace std; class CB1{ public: int a; CB1 (int x){ a=x; } void showa(){ cout<<"ClassCB1==>a="<<a<<endl; } }; class CB2{ public: int a; CB2 (int x){ a=x; } void showa(){ cout<<"ClassCB1==>a="<<a<<endl; } }; //多重繼承,兩個基類 class CD:public CB1,public CB2 { public: int a; //與兩個基類成員變量a重名 CD(int x,int y,int z):CB1(x) ,CB2(y){ a=z; } //與兩個基類成員函數showa()重名 void showa() { cout<<"Class CD==>a="<<a<<endl; } void print3a(){ cout<<"a="<<a<<endl; cout<<"CB1::a="<<CB1::a<<endl; cout<<"CB2::a="<<CB2::a<<endl; } }; int main(){ CB1 CB1obj(11); CB1obj.showa();//ClassCB1==>a=11 CD CDobj(101,202,909); CDobj.showa(); //調用派生類的showa() //Class CD==>a=909 CDobj.CB1::showa(); //調用基類的showa() //ClassCB1==>a=101 cout<<"CDobj.a="<<CDobj.a<<endl;//訪問派生類成員a //CDobj.a=909 cout<<"CDobj.CB2::a="<<CDobj.CB2::a<<endl; //CDobj.CB2::a=202 }
二、多重繼承的二義性
⚫ 若是派生類中新增了同名成員,則派生類成員將隱藏全部基類的同名成員。使用「派生類對象名.成員名」或「派生類對象指針->成員名」的方式能夠惟一標識和訪問派生類新增成員。這種狀況下,不會產生二義性。
⚫ 若是派生類中沒有新增同名成員,當知足訪問權限時,使用「派生類對象名.成員名」或「派生類對象指針->成員名」方式時,系統沒法判斷究竟是調用哪一個基類的成員,從而產生二義性。爲了不二義性,必須經過基類名和做用域分辨符來標識成員。
⚫ 當要訪問派生類對象中的某個變量時,添加「基類::」做爲前綴,指明須要訪問從哪一個基類繼承來的,從而能夠排除二義性。
三、繼承權限控制
設計繼承類時,須要使用繼承方式說明符指明派生類的繼承方式。繼承方式說明符能夠是public(公有繼承)、private(私有繼承)或protected(保護繼承)
⚫類型兼容規則是指在須要基類對象的任何地方,均可以使用公有派生類的對象來替代,也稱爲賦值兼容規則。在公有派生的狀況下,有如下3條類型兼容規則。
⚫上述3條規則反過來是不成立的。例如,不能把基類對象賦值給派生類對象。在進行替代以後,派生類對象就能夠做爲基類的對象使用了,但只能使用從基類繼承的成員。
⚫若是類B爲基類,類D爲類B的公有派生類,則類D中包含了基類B中除構造函數、析構函數以外的全部成員。這時,根據類型兼容規則,在基類B的對象能夠出現的任何地方,均可以用派生類D的對象來替代。假設有如下的聲明:
class B{…} class D : public B{…} B b1, *pb1; D d1;
⚫這時,派生類對象能夠隱含轉換爲基類對象,即用派生類對象中從基類繼承來的成員變量的值,逐個爲基類對象的成員變量的值進行賦值。b1=d1;
⚫派生類的對象也能夠用來初始化基類對象的引用,即:B &rb=d1;
⚫派生類對象的地址能夠隱含轉換爲指向基類的指針,即派生類對象的地址賦給基類指針:pb1=&d1;
⚫因爲類型兼容規則的引入,對於基類及其公有派生類的對象,可使用相同的函數統一進行處理。由於當函數的形參爲基類的對象(或引用、指針)時,實參能夠是派生類的對象(或指針),從而沒有必要爲每個類設計單獨的模塊,大大提升了程序的效率。
保護繼承中,基類的公有成員和保護成員都以保護成員的身份出如今派生類中,而基類的私有成員不能夠直接訪問。這樣,派生類的其餘成員能夠直接訪問從基類繼承來的公有和保護成員,但在類外經過派生類的對象沒法直接訪問它們。
class A{}; class B:private A{};//私有繼承 class C:protected A{};//保護繼承