派生類的作用域巢狀在其基類的作用域之內,如果乙個名字無法在派生類的作用域內無法正確解析,則編譯器將繼續在外層的基類作用域中尋找該名字的定義。
派生類中能重定義在其直接基類或間接基類中的名字,此時定義在內層作用域(即派生類)的名字將隱藏定義在外層作用域(即基類)的名字。
struct base
protected int mem;
};struct derived : base
int get_mem()
protected int mem; //@ 隱藏基類中的mem
};
可以通過作用域符來訪問被隱藏的基類成員:
struct derived : base
//...
};
作用運算子將覆蓋掉原有的查詢規則,並指示編譯器從base
類的作用域開始查詢mem
。
注意:除了覆蓋繼承而來的虛函式之外,派生類最好不要重用其他定義在基類中的名字。
如果派生類的成員與基類的某個成員同名,則派生類將在其作用域內隱藏該基類成員,即使派生類成員與基類成員的形參列表不一致,基類成員也會被隱藏。
struct base;
struct derived : base;
derived d;base b;
b.memfunc(); //@ 正確
d.memfunc(10); //@ 正確
d.memfunc(); //@ 錯誤,引數列表為空的基類成員函式被隱藏
d.base::memfunc(); //@ 正確
基類和派生類的虛函式接受的實參必須相同,否則就無法通過基類的引用或者指標呼叫派生類的虛函式。
class base;
class d1 : public base;
class d2 : public d1;
base bobj;d1 d1obj;d2 d2obj;
base* bp1 = &bobj,*bp2 = &d1obj,*bp3 = &d2obj;
bp1->fun(); //@ 呼叫base::fun
bp2->fun(); //@ 呼叫base::fun
bp3->fun(); //@ 呼叫d2::fun
d1 *d1p = &d1obj;d2 *d2p = &d2obj;
bp2->f2(); //@ 錯誤,base沒有名字為f2的成員
d1p->f2(); //@ 呼叫d1::f2
d2p->f2(); //@ 呼叫d2::f2
base *p1 = &d2obj;d1 *p2 = &d2onj;d2 *p3 = &2dobj;
p1->fun(42); //@ 錯誤,base中沒有接受乙個int的fun
p2->fun(42); //@ 靜態繫結,呼叫d1::fun(int)
p3->fun(42); //@ 靜態繫結,呼叫d2::fun(int)
成員函式無論是否是虛函式,都可以被過載,派生類可以覆蓋過載函式的0個或多個例項,如果派生類希望所有的過載版本對它來說都是可見的,那麼它就需要覆蓋所有的版本,或者乙個也不覆蓋。
有時候只需要覆蓋過載集合中的乙個版本,而不得不覆蓋基類中的每乙個版本,顯然很麻煩。一種的好的解決辦法是為過載成員提供一條using
宣告語句,這樣就不需要覆蓋基類中的每乙個過載版本。using 宣告語句指定了乙個名字而不指定形參列表,所以一條基類成員函式的using
宣告語句就能把該函式的所有過載例項新增到派生類的作用域中,此時派生類只需要定義其特有的版本即可,無需為繼承而來的。
繼承中的類作用域 1
每個類定義自己的作用域,當存在繼承關係時,派生類的作用域巢狀在其基類的作用域中。1 乙個物件 引用或指標的靜態型別決定了該物件的哪些成員是可見的,即使靜態型別與動態型別不一致 當使用基類的引用或指標時,會發生這種情況 2 派生類的成員將隱藏同名的基類成員,使用作用域來使用乙個被隱藏的基類成員 3 名...
C 中的類作用域
在類中定義的名稱 如類資料成員名和類成員函式名 的作用域都為整個類,作用域為整個類的名稱只在該類中是已知的,在類外是不可知的。因此,可以在不同類中使用相同的類成員名而不會引起衝突。作用域為類的常量 class bakery 通過上述描述建立乙個由所有物件共享的常量的方式有誤!因為類宣告只是描述了物件...
類的作用域
更多c 類的基本概念 每個類都會定義它自己的作用域。在類的作用域外,普通的資料和函式成員只能由物件 引用或者指標使用成員訪問運算子來訪問。對於類型別成員則使用作用域運算子訪問。不論哪種情況,跟在運算子之後的名字都必須是對應類的成員。作用域和定義在類外部的成員 乙個類就是乙個作用域很好地解釋為什麼當我...