C++第七節:繼承

繼    承

1、子類與父類

     1.1 子類自動繼承父類所有成員(包括成員函數、成員變量),除了構造函數、析構函數和重載的賦值運算符。

     1.2 子類在用父類所有功能的同時,也擴展了一些新的功能。即子類成員分爲兩部分,繼承自父類的部分和子類獨有的成員即子類自己擴展的成員。

     1.3 子類也擁有父類的私有成員,但子類不能通過自己擴展的函數來訪問繼承自父類的私有成員,而必須通過繼承自父類的公有成員函數來訪問。

     1.4 在子類中調用被覆蓋的父類版本的函數時,在函數名前加Base::。

     1.5 面向對象最重要的目標:實現代碼複用。通過繼承子類自動擁有了父類代碼,大大減少了代碼書寫量,十分方便維護程序(只需修改父類代碼,子類就自動隨着更改)

2、覆蓋與重載

     2.1 子類可以自己實現與父類成員函數原型相同(函數名、函數列表)的成員函數,稱爲覆蓋,覆蓋是函數重載的特例,覆蓋一定發生在繼承的過程中。

     2.2 發生覆蓋時,根據調用者對象本身的類型來確定,無法根據參數列表確定。

     2.3 ------

    //1.重寫必須繼承,重載不用。

    //2.重寫的方法名,參數數目相同,參數類型兼容,重載的方法名相同,參數列表不同。

    //3.重寫的方法修飾符大於等於父類的方法,重載和修飾符無關。

    //4.重寫不可以拋出父類沒有拋出的一般異常,可以拋出運行時異常

    //重寫是子類的方法覆蓋父類的方法,要求方法名和參數都相同

    //重載是在同一個類中的兩個或兩個以上的方法,擁有相同的方法名,但是參數卻不相同,方法體也不相同

    一、重寫(override

    override是重寫(覆蓋)了一個方法,以實現不同的功能。一般是用於子類在繼承父類時,重寫(重新實現)父類中的方法。

    重寫(覆蓋)的規則:

    1、重寫方法的參數列表必須完全與被重寫的方法的相同,否則不能稱其爲重寫而是重載.

    2、重寫方法的訪問修飾符一定要大於被重寫方法的訪問修飾符(public>protected>default>private)。

    3、重寫的方法的返回值必須和被重寫的方法的返回一致;

    4、重寫的方法所拋出的異常必須和被重寫方法的所拋出的異常一致,或者是其子類;

    5、被重寫的方法不能爲private,否則在其子類中只是新定義了一個方法,並沒s有對其進行重寫。

    6、靜態方法不能被重寫爲非靜態的方法(會編譯出錯)。

    二、overload是重載,一般是用於在一個類內實現若干重載的方法,這些方法的名稱相同而參數形式不同。

    重載的規則:

    1、在使用重載時只能通過相同的方法名、不同的參數列表實現。不同的參數列表可以是不同的參數類型,不同的參數個數,不同的參數順序(參數類型必須不一樣);

    2、不能通過訪問權限、返回類型、拋出的異常進行重載;

    3、方法的異常類型和數目不會對重載造成影響;

    多態的概念比較複雜,有多種意義的多態,一個有趣但不嚴謹的說法是:繼承是子類使用父類的方法,而多態則是父類使用子類的方法。

    一般,我們使用多態是爲了避免在父類裏大量重載引起代碼臃腫且難於維護。

    

    重定義(隱藏)是指派生類的函數屏蔽了與其同名的基類函數,規則如下:

    a 如果派生類的函數和基類的函數同名,但是參數不同,此時,不管有無virtual,基類的函數被隱藏。

    b 如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有vitual關鍵字,此時,基類的函數被隱藏。

    

    重載和重寫的區別:

    1)範圍區別:重寫和被重寫的函數在不同的類中,必須是繼承,重載和被重載的函數在同一類中。

    2)參數區別:重寫與被重寫的函數參數列表一定相同,重載和被重載的函數參數列表一定不同。

    3virtual的區別:重寫的基類必須要有virtual修飾,重載函數和被重載函數可以被virtual修飾,也可以沒有。

3、訪問修飾符

     3.1 ------

public:
 1、修飾class裏的成員,這些成員可以在class的內部被訪問,也可以在外部被訪問。
 2、公有成員可以被繼承。
 3、當一個class作爲父類被繼承時,可以用public來修飾。如下:
 class Child : public Father
 {   };
 此時,父類中的publicprotected成員都可以被子類繼承,並且修飾符與父類一樣。
 
 protected:
 1、修飾class裏的成員,這些成員可以在class的內部被訪問,也可以被友元類和友元方法訪問,不可以在外部被訪問。
 2、保護型成員可以被繼承。
 3、當一個class作爲父類被繼承時,可以用protected來修飾。如下:
 class Child : protected Father
 {   };
 此時,父類中的publicprotected成員都可以被子類繼承,並且修飾符都是protected
 
 private:
 1、修飾class裏的成員,這些成員只可以在class的內部被訪問。
 2、私有成員可以被繼承,但不能被子類訪問。
 3、當一個class作爲父類被繼承時,可以用private來修飾。如下:
 class Child : private Father
 {   };

 此時,父類中的publicprotected成員都可以被子類繼承,並且修飾符都是private

A、簡單繼承類

Base.h

#ifndef __C__No803Class__Base__
#define __C__No803Class__Base__

#include <iostream>
using namespace std;
class Base
{
private:
    int bnumber;
public:
    Base (int n);
    int getNumber();
    void print ();
};
#endif /* defined(__C__No803Class__Base__) */
Base.cpp
#include "Base.h"
Base::Base (int n) : bnumber(n) {}

int Base::getNumber()
{
    return bnumber;
}
void Base::print ()
{
    cout << "bnumber is " << bnumber << endl;
}
Derived.h
#ifndef __C__No803Class__Derived__
#define __C__No803Class__Derived__

#include <iostream>
#include "Base.h"
//using namespace std;
class Derived : public Base
{
private:
    int dnumber;
public:
    Derived (int i, int j);
    void print();
};
#endif /* defined(__C__No803Class__Derived__) */
Derived.cpp
#include "Derived.h"
Derived::Derived (int i, int j):Base(i)
{
    dnumber = j;
}
void Derived::print()
{
    cout << "bnumber is " << getNumber() << " ";  //與下面等價
    Base::print();
    //cout << bnumber << endl;  //子類不能直接訪問父類的私有成員變量
    cout << "dnumber is " << dnumber << endl;
    //OOP三大特性:繼承,多態,封裝
}
main.cpp
#include <iostream>
#include "Derived.h"
int main(int argc, const char * argv[])
{
    Base a(2);
    a.print();
    
    Derived b (3, 4);
    b.print();
    
    cout << "Base part of b " ;
    b.Base::print();
    
    return 0;
}
B、簡單探究訪問修飾符
Father.h
#ifndef __C__No803Class__Father__
#define __C__No803Class__Father__

#include <iostream>
using namespace std;
class Father
{
public:
    int i;
private:
    int j;
protected:
    int k;
public:
    Father(int ii, int jj, int kk);
    int getI();
    int getJ();
    int getK();
    void print();
};
#endif /* defined(__C__No803Class__Father__) */
Father.cpp
#include "Father.h"
Father::Father(int ii, int jj, int kk)
{
    i = ii;
    j = jj;
    k = kk;
}
int Father::getI()
{
    return i;
}
int Father::getJ()
{
    return j;
}
int Father::getK()
{
    return k;
}
void Father::print()
{
    cout << "i = " << i << " ";
    cout << "j = " << j << " ";
    cout << "k = " << k << endl;
}
Son.h
#ifndef __C__No803Class__Son__
#define __C__No803Class__Son__

#include <iostream>
#include "Father.h"
class Son : private Father
{
public:
    int a;
private:
    int b;
protected:
    int c;
public:
    Son(int ii, int jj, int kk, int aa, int bb, int cc);
    void print();
};
#endif /* defined(__C__No803Class__Son__) */
Son.cpp
#include "Son.h"
Son::Son(int ii, int jj, int kk, int aa, int bb, int cc):Father(ii, jj, kk)
{
    a = aa;
    b = bb;
    c = cc;
}
void Son::print()
{
    Father::print();
    cout << "i = " << i << " ";
    //cout << "j = " << j << " ";  //public,protected,private下,私有成員變量子類無法訪問
    cout << "k = " << k << endl;
    cout << getI() << getJ() << getK() <<endl;
    cout << "a = " << a << " ";
    cout << "b = " << b << " ";
    cout << "c = " << c << endl;
}
main.cpp
#include "Son.h"
int main ()
{
    Father t(1, 2, 3);
    t.print();
    Son s(0, 9, 8, 7, 6, 5);
    //s.Father::print();  //protect,private下,該語句編譯不通過
    s.print();
    
    return 0;
}

發佈了31 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章