7、继承
1.繼承
??? 兒子繼承父親的遺產,兒子擁有父親所有的成員變量和成員函數。兒子也可以擁有父親沒有的成員變量和成員函數。
??? 子類與父類繼承的關系,
??? 也就是說:
??? (1)子類擁有父類所有的成員變量和成員函數(除了構造函數和析構函數)。
??? (2)子類的對象可以當作父類的對象使用(認為子類是特殊的一個父類)
??? (3)子類可以用父類沒有的成員變量和成員函數。
class Parent { public:Parent();~Parent();void pri(); private:int a; }; Parent::Parent() {a = 100; } Parent::~Parent() { } void Parent::pri() {cout << "a = " << a << endl; } class Child : public Parent // 繼承父類 { }; int main() {Parent p1;p1.pri();Child c1;c1.pri();while (1); }??? 都可以打印出? a = 100;,這里就涉及到繼承的方式的問題:
class 子類名 : 繼承的方式 父類名 { }??? 當沒有指定 繼承的方式(public,private)的話,那么就是默認為私有的繼承。
繼承的權限:
繼承的方式
public 父類在子類中,保持原有的訪問的級別,子類可以訪問父類的共有成員,私有成員不能被訪問
private 父類在子類中,全部變為private的訪問級別,那么子類不可以訪問父類所有的成員
??? 一般來說,我們都是 public 的方式進行繼承,但是 private 成員可以被子類繼承,但是不能被子類訪問,所以,就有了了繼承的關鍵字:protected
?
關鍵字 protected:
??? 介于 private 和 public 之間,也就是說,被 protected 修飾的變量:
??? (1)可以在類內被訪問
??? (2)可以被子類訪問
??? (3)不可以被外接(通過對象,不管是父類還是子類都不可以被訪問)訪問
class Parent { public:Parent();~Parent();void pri(); protected: // 被保護的,子類就可以訪問int a; }; Parent::Parent() {a = 100; } Parent::~Parent() { } void Parent::pri() {cout << "a = " << a << endl; } class Child : public Parent // 繼承父類 { protected: // int b; public:void setDATA(int a, int b){this->a = a;this->b = b; // b 是被保護的,所以可以被子類訪問 }void cintData(){cout << "a = " << a <<" "<< "b = " << b << endl;} }; int main() {Parent p1;p1.pri();Child c1;c1.setDATA(1, 2);c1.cintData();while (1); }??? 如果不是被 protected 修飾,而是被 private 修飾的話,那么子類壓根就沒有權限去訪問父類的 private 的成員變量,這個就不是我們想看到的,
權限的設置:
(1)需要被外接訪問,則使用 public
(2)只能在類內被訪問的成員的話,則是設置為 private
(3)只能在當前類內和子類中的訪問的成員,則是設置為 protected
繼承成員對外的訪問的屬性: MAX(繼承的方式,父類的訪問的級別)
繼承訪問級別設置的原則:
需要被外接(對象)訪問的成員直接設置為: public
只能在類的內部被訪問的成員設置為 : private
只能在當前類和子類中訪問的成員設置為 : protected
繼承中的構造和析構函數:
??? 子類和父類的繼承,那么子類已經是繼承了父類所有的成員函數和成員變量(除了構造函數和析構函數、拷貝構造函數、operator函數、友元函數沒有被繼承、)。
子類的對象構造的時候,會調用父類的構造函數。父類的構造函數完成父類的構造,而子類的構造函數則是完成自己新增的成員進行初始化;因此析構的函數也是一樣的,子類的就析構自己的就可以,繼承的東西,就讓父類的析構函數自己去完成清理的工作。
??? 可見,子類對象創建的時候,是先自動調用父類的構造函數,執行完畢之后再指定子類的構造函數;虛構函數是先析構子類的構造函數,然后再執行父類的析構函數;同時可以看到,析構函數是構造函數的完全相反地執行。
繼承與組合:
??? 組合就是自身的成員是其他類的對象,這個就叫組合,那么構造函數和析構函數的執行的順序,
?? 構造函數執行的順序: 先父母,在別人,最后自己;首先可以看到,child 繼承 父母,而父母則是繼承 obj,很顯然必須是先執行 obj 的打印(構造函數),再執行 parent 的構造函數;接著是別人,child 里面有兩個 對象作為自己的成員變量,所以就執行兩次 obj 的構造函數;最后才是執行自己的 child 打印
?
子類和父類的成員同名的時候:
(1)子類的成員變量和父類的成員變量同名的時候:
??? A、子類依然繼承父類同名的成員名
??? B、子類中通過作用域分別符 :: 來進行區分是哪一個成員
??? C.、同名的成員存儲在內存中的不同的位置
class Parent { protected:int i; public: }; class Child : public Parent { protected:int i; public:Child(int i){Parent::i = i; // 通過作用域進行指定同名的成員變量Child::i = i + 1;}void pri(){ // 打印父類和子類的 i 值cout << "parent ::i = " << Parent::i << endl;cout << "Child ::i = " << Child::i << endl;cout << "parent i dizhi" << &(Parent::i) << endl;cout << "parent i dizhi" << &(Child::i )<< endl;} }; int main() {Child c1(5);c1.pri();while (1); }??? 成功打印出: 5 和 6 ,而且 不同 i 的地址是不一樣的,也就是說,i 是存儲在不同的內存的位置;通過 類名 + ""(作用域操作符)進行區分;
(2)子類與父類的函數同名:
class Parent { public:void f(){cout << "f A" << endl;} }; class Child : public Parent { public:void f(){cout << "f B" << endl;} }; int main() {Child c1;c1.f();while (1); }while (1);
}
??? 輸出的結果是: f B,當子類與父類函數名相同的時候,那么子類是沒有辦法調用父類的同名函數的,因為父類的同名函數被編譯器做隱藏的處理,
轉載于:https://www.cnblogs.com/qxj511/p/5217361.html
總結
- 上一篇: 提高代码质量:如何编写函数
- 下一篇: 标准CSV解析