每個類定義自己的作用域,在作用域中定義類的成員,當存在繼承關係時,派生類的作用域巢狀在其基類的作用域內。當乙個成員名字在派生類的作用域內無法解析的時候,編譯器將繼續在外層的基類作用域中尋找該名字的定義。
舉個例子:類b中有乙個函式名為f,類d繼承自類b,當通過d的物件呼叫函式f時會有如下流程:
1.首先在d中查詢,這一步沒有找到名字f;
2.因為d是b的派生類,所以接下來在b中查詢,此時找到名字f,所以使用的f函式最終被解析為b中的f。
因此,當呼叫p->mem()或obj.mem()時,將依次執行以下步驟:
1.首先確定p(或obj)的靜態型別。因為呼叫的是乙個成員,因此該型別必然是類型別;
2.在p(或obj)的靜態型別對應的類中查詢mem().如果找不到,則依次在直接基類中不斷查詢直到繼承鏈的頂端,如果仍然找不到,編譯器將報錯;
3.一旦找到mem,將進行常規型別檢查以確定這次的呼叫是否合法;
4.假如呼叫合法,則編譯器將根據呼叫的是不是虛函式而產生不同的**。
名字衝突與繼承:
派生類能重用定義在其直接基類或者間接基類中的名字:
struct base
protected:
int mem;
};struct der:base
int getm()
//通過作用域運算子使用隱藏的成員
int get_b_m()
protected:
int mem;
};int main(void)
名字檢查優於型別判斷:
即使在派生類成員與基類成員的引數列表不相同,基類成員依然會被隱藏:
class base
};class sb:public base
};int main(void)
編譯器首先在sb中查詢名字f,因為在sb中確實有乙個名為f的成員,因此查詢過程就終止了,而sb中的f需要乙個引數,呼叫的語句無法提供實參,所以呼叫語句錯誤。
虛函式與作用域:
以上也是基類和派生類中的虛函式必須有相同引數列表的原因:
class base;
class d1:public base;
class d2:public d1;
覆蓋過載的函式:
和其它函式一樣,成員函式無論是不是虛函式都能被過載。派生類可以覆蓋過載函式的0個或多個例項。如果派生類希望所有的過載版本對它來說都是可見的,那麼他就需要覆蓋所有版本,或者乙個也不覆蓋。
有時乙個類僅需覆蓋過載集合中的一些而非全部函式,此時,如果不得不覆蓋基類的每乙個版本的話,操作將變得極為繁瑣。
一種好的解決方法就是使用using關鍵字,因為using宣告語句指定的是乙個名字而不指定引數列表,所以一條基類成員函式的using語句就能把該函式的所有過載例項新增到派生類的作用域中。此時,派生類只需要定義其特有的函式就可以了,而無需為繼承而來的其它函式重新定義。
class base
int f(int i){}
int f(int i,int j){}
int f(double d){}
int f(double d,double e){}
void f(int a,double v){}
void f(int e,char a){}
double f(char s){}
char f(int r,char s,double a){}
char f(double g,char w){}
char f(double d,int f){}
};class sb:public base //在這裡只過載了乙個函式,
};class sb2:public base;
class sb3:public base //只過載部分
};int main(void)
C Primer第五版筆記 關聯容器
一 型別 關聯容器支援高效的關鍵字查詢和訪問,標準庫中兩個主要的關聯容器是map和set。map中的元素是鍵值對關鍵字表示索引。set中每個元素只包含乙個關鍵字,set支援高效的關鍵字查詢。關聯容器根據三個特性可以分為8種 1 set還是map 2 關鍵字是否可以重複,允許重複的容器名字中都包含單詞...
C Primer第五版筆記 動態陣列
allocator類 為了讓new分配乙個物件陣列,需要在型別名後跟方括號,括號中是分配物件的數目,該數目必須是整型,但不必是常量 new t 分配的記憶體並不是得到乙個陣列,而是得到乙個陣列元素型別的指標,因此不能對動態陣列呼叫begin和end 與普通陣列不同的是,普通陣列不能定義長度為0的陣列...
C Primer第五版筆記 拷貝控制
拷貝賦值函式 析構函式 三 五法則 default和阻止拷貝 乙個類通過定義五種特殊的成員函式來控制其拷貝 賦值 移動以及銷毀操作 拷貝建構函式 拷貝賦值運算子 移動建構函式 移動賦值運算子和析構函式。這些操作都是拷貝控制操作。當實現自己的類的時候要想好在做這些操作時的規則,因為編譯器通常會自動生成...