C++ 繼承真正在做的事系列【重載,重寫/覆蓋,隱藏】

這三個概念是討論的函數名相同的情況,不要後面要問怎麼函數名不同的時候不討論呢?那你現在最好要確定下函數名不同值得討論嗎?

-----------------------------------------------------------------------------------------------------------------------------------

     
   這個B裏面增加什麼東西會是上面的概念呢?

-----------------------------------------------------------------

重載:同一個類中定義的函數名相同,參數不同的方法。如果和繼承的函數的函數名相同,就要涉及到重寫和隱藏。其實不應該拿到這裏來討論的,因爲它是指在同一個類中定義的。

----------------------------------------------------------------
重寫:這個就涉及到大家常用的virtual關鍵字了。也就是基類函數用virtual修飾,子類中定義一個函數與其同名,而且參數相同。這裏就是所謂的多態。如果您還不知道多態,請百度下。 當基類中的某個函數virtual後,子類創建基類對象,並用子類的重寫的方法放入基類本來分好的代碼段中,把以前的代碼覆蓋掉,也就是把函數重寫了。其實這就是所謂的動態綁定技術。這樣的話無論你是用基類指針還是派生類指針訪問該函數,執行的都是子類中重新寫的代碼。

----------------------------------------------------------------
隱藏: 什麼是隱藏?看代碼

例1


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
    
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}

結果:A:fun1
      A:fun1

 

這是正常情況下,B繼承了A的fun1,所以用兩種類型的指針調用的都是同一個fun1。下面在B中分3種情況加一個同名函數。

 

例2


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
        void fun1()
{
   cout<<"B:fun1"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}
結果:A:fun1
      B:fun1
子類同名函數,參數相同,但基類函數沒有virtual,這個時候是隱藏。用子類的指針只能訪問子類的那個fun1,不能訪問繼承自基類的fun1,其實它仍然存在與基類的代碼段中,
因爲用A類型指針能頭訪問它。這也是隱藏名字的由來,基類的fun1對子類指針隱藏了,躲貓貓了,但仍然存在,要通過基類指針訪問。

 

例3


class A

public: 
void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public: 
        void fun1(int i)
{
   cout<<"B:fun1"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); //這裏編譯報錯
return 0;
}
結果:error C2660: “B::fun1” : 函數不接受 0 個參數
基類同名函數非virtual,子類參數不同。那麼當用子類指針進行訪問繼承自A的fun1時,會訪問不了,報錯。當你註釋掉以後,用A的指針還是能訪問的。

 

例4


class A

public: 
virtual void fun1()
{
   cout<<"A:fun1"<<endl;
}
};

class B:public A
{
public:

void fun1(int i)
{
   cout<<"B:fun1 int"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])

A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); 
return 0;
}
結果:和上一種情況一樣。
基類同名函數是virtual的,子類定義了一個同名參數不同的,但還是隱藏的。


結論:子類和基類定義同名函數的總共4種情況(virtual兩種,參數兩種,總共2*2)都討論過了。綜上所述,當基類的某函數聲明爲virtual,使用動態綁定技術,當最終創建子類對象的時候,如果子類種有同名且參數相同即完全一樣的函數的時候,這個時候基類的virtual函數代碼才最終確定。也實現了函數的重寫。當創建子類對象的時候,如果沒碰到同名參數相同的函數,會使用基類定義的代碼。這個時候如果子類也定義了一個同名的函數,那麼會隱藏掉基類的同名函數。這就是4種情況的另外3種情況。

補充:

class A
{
public:
virtual void show()
{
   cout<<"ok in a"<<endl;
}
};
class B :public A
{

void show()
{
   cout<<"ok in b"<<endl;
}
};

int main()
{
B *bp=new B;
A *ap=(A*)bp;
ap->show();
//bp->show(); //出現編譯錯誤 error C2248: “B::show” : 無法訪問 private 成員(在“B”類中聲明)
}

出現編譯錯誤,是因爲B中的show()是private的。bp調用時權限是B定義的,ap調用權限是A定義的。

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