關於繼承,函數的繼承

1. 子類擁有了父類的public財產(私有成員其實也有,但是訪問不了),通過子類調用函數時,編譯器先在子類中找相應的函數,找不到的話再去父類找。

    如此一來,如果父類和子類定義了一樣的函數(包括參數列表),子類的函數會覆蓋父類函數。

                       如果,父類定義了子類的同名函數,但是參數列表不同,子類的也會被覆蓋隱藏,如

                                   果想通過子類調用父類的函數,需要顯示的說明,比如 b.A::XXXX(p1, p2)

 

#include <iostream>

using namespace std;

class A
{
public:
    A() {}
    ~A() {}
    void print() { cout << "This is A\n"; }
};


class B: public A
{
public:
    B() {}
    ~B() {}
    void print() { cout << "This is B\n"; }
};

int main()
{
    A a;
    B b;

    A *pa = &a;
    B *pb = &b;

    pa->print();
    pb->print();

    getchar();

    return 0;
}

所以這段代碼輸出 This is A 和 This is B

 

2. 下面的代碼

#include <iostream>

using namespace std;

class A
{
public:
    A() {}
    ~A() {}
    void print() { cout << "This is A\n"; }
};


class B: public A
{
public:
    B() {}
    ~B() {}
    void print() { cout << "This is B\n"; }
};

int main()
{
    A a;
    B b;

    A *pa = &a;
    A *pb = &b;                 // 這行是關鍵

    pa->print();
    pb->print();

    getchar();

    return 0;
}

居然,輸出是 兩個 “This is A”。

 

 

3. 所以虛函數便應運而生,很好解決了同名函數繼承的多態問題。

#include <iostream>

using namespace std;

class A
{
public:
    A() {}
    ~A() {}
    virtual void print() { cout << "This is A\n"; }
};


class B: public A
{
public:
    B() {}
    ~B() {}
    void print() { cout << "This is B\n"; }
};

int main()
{
    A a;
    B b;

    A *pa = &a;
    A *pb = &b;

    pa->print();
    pb->print();

    getchar();

    return 0;
}

輸出是  This is A 和 This is B

 PS。虛函數的多態,嚴格按照函數名+參數名。也就是說子類和父類的函數名和參數都得完全一致。
          而函數隱藏卻不需要這麼嚴格,只要函數名一樣的就隱藏函數。

 

 

 

覆蓋
如果派生類覆蓋了基類中的成員函數或成員變量,則當派生類的對象調用該函數或
變量時是調用的派生類中的版本,當用基類對象調用該函數或變量時是調用的基類中的版本。

隱藏
看下邊這個例子,B繼承A 爲什麼main函數執行fun(x),fun(x,y)時編譯通不過
class A
{
public:

void f(int i,int j){
i=i+j;
cout<<i<<endl;
}
void f(int i){
cout<<i<<endl;
}
};
class B:public A//private A
{

public:
//using A::fun;
/*void f(){
a=10;
cout<<a<<endl;
}*/
private:
int a;
};
int main(){
B m;
m.f(5,1);
//m.A::f(5,1);
}


其實很簡單
隱藏基類成員函數的情況:如果在派生類中定義了一個與基類同名的函數,不管這個函數的參數列表是不是與基類
中的函數相同,則這個同名的函數就會把基類中的所有這個同名的函數的所有重載版本都隱藏了,這時並不是在派
生類中重載基類的同名成員函數,而是隱藏,比如類A中有函數f(int i,intj)和f(int i)兩個版本,當在從A派生出的類
B中定義了基類的f()函數版本時,這時基類中的fun(int i)和f(int i,int j)就被隱藏了,也就是說由類B創建的對象比如
爲m,不能直接訪問類A中的f(int i)版本,即使用語句m.f(2)時會發生錯誤。

怎樣使用派生類的對象訪問基類中被派生類覆蓋或隱藏了的函數或變量:

方法 1 使用作用域運算符::,在使用對象調用基類中的函數或變量時使用作用域運算符即語句 m.A::f(2),這
時就能訪問基類中的函數或變量版本。注意,訪問基類中被派生類覆蓋了的成員變量只能用這種方法

方法 2 使用 using:該方法只適用於被隱藏或覆蓋的基類函數,在派生類的類定義中使用語句 using 把基類的
名字包含進來,比如using A::f;就是將基類中的函數f()的所有重載版本包含進來,重載版本被包含到子類之
後,這些重載的函數版本就相當於是子類的一部分,這時就可以用派生類的對象直接調用被派生類隱藏了的
基類版本,比如 m.f(2),但是使用這種語句還是沒法調用基類在派生類中被覆蓋了的基類的函數,比如 m.f()
調用的是派生類中定義的函數f,要調用被覆蓋的基類中的版本要使用語句m.A::f()纔行。

在派生類的函數中調用基類中的成員變量和函數的方法:就是在函數中使用的被派生類覆蓋的基類成員變量或函數
前用作域解析符加上基類的類名,即a::f()就是在派生類的函數中調用基類中被派生類覆蓋了的函數f()的方法。

派生類以私有方式被繼承時改變基類中的公有成員爲公有的方法:
使用::作用域運算符,不提倡用這種方法,在派生類的 public 後面用作用域運算符把基類的 公有成員包函進
來,這樣基類的成員就會成爲派生類中的公有成員了,注意如果是函數的 話後面不能加括號 ,如A::f;如果
f是函數的話不能有括號
使用using語句,現在一般用這種方法,也是在派生類的public使用using把基類成員包函進來,如using A::f。

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