建構函式和析構函式中的虛函式,構造和析構也是分階段的,也就是說從無到基類物件,再到派生類物件,從派生類物件到基類物件,再到無。
這中間有乙個狀態就是基類物件,此時直接或間接呼叫虛函式,只能是基類中的版本,因為後邊的還沒形成呢。
因為如果使用派生類中的版本,可能需要訪問派生類物件的成員,而這些還不存在,為了避免這個崩潰風險,就給遮蔽了。
繼承情況的類作用域:
派生類的作用域巢狀在基類作用域中,如果不能在派生類作用域中確定名字,就在外圍基類作用域中查詢該名字的定義。
靜態型別的優先權
在item_base和bulk_item中間的disc_item中加一函式,靜態繫結吧。。。靜態繫結是編譯時而非執行時,也就是說編譯時查名字discount_policy()位置
利用指標和引用來找是動態的此例沒虛函式,這樣bulk_item先找自己,根據作用域巢狀,再找直接基類disc_item,而如果指標是基類型別的,因為根本沒宣告,找不到discount_policy()函式。
class disc_item : public item_base
};
bulk_item *bulkp = &bulk; //ok:static and dynamic types are the same
item_base *itemp = &bulk; //ok:static and dynamic types differ
bulkp->discount_policy(); //ok:bulkp has type bulk_item*
itemp->discount_policy(); //error:itemp has type item_base*
名字衝突與繼承:
基本也沒什麼東西,不過就是作用域操作符
int get_mem() //returns derived::mem
int get_base_mem() //returns base::mem
規律是這麼個規律,不過也是要盡量避免的,不出現最好
就和那句典型的setdata()一樣
不一樣的是那個是函式體內形參覆蓋類中成員,這裡是派生類成員覆蓋同名的基類成員
pe23_2.cpp 原題的關於基類和派生類的定義錯誤太多,這是改版
比較奇特的發現:第乙個,基類的foo_bar和派生類的foo_bar()沒有名字衝突,而基類的bar和派生類的bar(base *pb)衝突
第二個,不光有基類派生類的名字衝突問題,解決了名字遮蔽問題,還要遇到派生類不能訪問基類protected成員問題
//原題有問題,修改
#includestruct base ;
struct derived : public base ;
//第二題,錯誤一樣,試圖給base::bar賦值1024,其實被遮蔽了,結果是bar認為1024是個不恰當的字串初始位址,提示是不是缺&
//void derived::foo_bar()
//第三題,似乎沒錯,除非題目的定義錯了,原意是不是派生類的方法foo_bar()遮蔽基類的foo_bar,
//實際上基類的成員和派生類的成員函式同名也不允許啊。。。。。。
//其實還有問題,基類是protected,直接訪問不成靜態繫結也不成~!!!!!!!!!!!!!!!!
//bool derived::bar(base *pb)
//
int main()
作用域與成員函式:
derivedoverload.cpp
小結:和區域性函式不會過載全域性函式一樣,只要函式名相同,引數列表無所謂,派生類重定義的覆蓋作用大於過載功能,正常情況下派生類要麼不過載基類成員,要麼全覆蓋掉
用using 宣告,可以引入基類成員(相當於都複製過來一遍),引入後就相當於在派生類作用域內展開過載了
//基類和派生類的成員函式不能過載,是覆蓋,在派生類重定義成員函式的前提下,即使引數不對,直接找不到,也不會去基類找的,
//不過也可以用base::直接呼叫基類成員
//當然,使用using base::memfcn引入基類成員,就可以過載了。。
#includestruct base
};struct derived : base //hides memfcn in the base
};int main()
虛函式與作用域:
review:動態繫結的前提條件--通過指標或引用呼叫虛成員。
當我們這樣做時,編譯器將在基類中查詢函式(怎麼沒說後續去派生類找啊~)。假定找到了名字,編譯器就檢查實參是否與形參匹配。
這就可以理解為什麼虛函式要求基類和派生類中有同一原型。
如果實參不同,就沒有辦法通過基類型別的ptr和ref呼叫派生類函式,文字不太好理解,看看code。
也就是說ptr和ref意味著動態繫結,動態繫結要帶著引數一塊呼叫的,如果引數不匹配,base*是不在乎derived中有什麼的。
/*virtualandscope.cpp*/
//虛函式與作用域,示例--重點在d2,d2中既有虛函式,又有重定義覆蓋。。。
#includeclass base
};class d1 : public base //parameter list differs from fcn in base
//d1 inherits definition of base::fcn()
//引數列表不匹配不算虛函式。雖然繼承base::fcn(),但是d1::fcn()還是沒有的
};class d2 : public d1 //nonvirtual function hides d1::fcn(int)
int fcn() //redefines virtual fcn from base
};int main()
小改版,base中取消virtual,d1加virtual,base和d1過載,d1和d2虛函式繫結,然後動態呼叫
using base::fcn;
virtual int d1::fcn(int)
d1 *dp2 = &d1obj, *dp3 = &d2obj;
dp2->fcn();
dp2->base::fcn();
dp2->fcn(2);
dp3->fcn();
dp3->base::fcn();
dp3->fcn(2);
關鍵概念:名字查詢與繼承
理解c++繼承層次的關鍵在於理解如何確定函式呼叫,確定函式呼叫遵循以下4個步驟
在譯本p501(原版594)頁尾。。。
習題15.24
//習題,懶得實現了,簡單問題,乙個是經過複製構造,複製出了item_base物件,乙個是動態的,識別出是bulk_item物件,用virtual
pe15_25.cpp 有點小困惑,過載好像不關心返回型別著,但是虛函式呢。
另外,前邊能正常執行的,後來連derived d;都不允許了,提示很詭異。我又沒呼叫copy(),必須先完成定義麼?是說copy()很特殊
。。(mark)
//四小題,base中的虛函式,加入derived打算定義自己的這個虛函式版本,確定哪個宣告是錯誤的
#includeclass base //d)
};class derived : public base //d)沒錯,const不影響虛函式
};int main()
錯誤提示
g++ -wall -o "pe15_25" "pe15_25.cpp" (in directory: /home/huqinwei/cppworkspace/chap15)
/tmp/ccl8gimw.o: in function `base::base()':
pe15_25.cpp:(.text._zn4basec2ev[_zn4basec5ev]+0x8): undefined reference to `vtable for base'
/tmp/ccl8gimw.o:(.rodata._ztv7derived[vtable for derived]+0x8): undefined reference to `base::copy(base*)'
/tmp/ccl8gimw.o:(.rodata._zti7derived[typeinfo for derived]+0x8): undefined reference to `typeinfo for base'
collect2: ld returned 1 exit status
compilation failed.
繼承情況下類的作用域
在繼承情況下,派生類的作用域巢狀在基類作用域中。因此,如果不能在派生類作用域中確定的名字,就在外圍基類作用域中查詢該名字的定義。在基類和派生類中使用同一名字的成員函式,其行為與資料成員一樣 在派生類作用域中派生類成員將遮蔽基類成員。即使函式原型不同,基類成員也會被遮蔽。如果要訪問被遮蔽的基類成員,需...
C 中繼承情況下的類作用域
首先,每乙個類都保持著自己的作用域,在該作用域中定義了成員的名字。物件 引用或指標的靜態型別決定了物件能夠完成的行為 c primer 這裡能夠完成的行為,應該說是能夠使用的變數名 資料和方法 這些變數名是定義在呼叫它的物件 引用或指標的靜態型別中的。為什麼將行為改為變數名,是因為我覺得行為是處理事...
Java 繼承情況下例項變數的初始化
package scjp class x class y public class demo65 extends x public static void main string args 執行結果 yxyz 分析 1.new demo65 1.2.demo65的超類是x,所以 new x 1.2....