新聞中心
下面3個(gè)小問(wèn)題都是我認(rèn)為C++ Beginner應(yīng)該能夠解答或辨別清楚的。希望我們能通過(guò)題目挖掘更多的信息,而不僅僅局限在解題。我最喜歡說(shuō)的話:能力有限,所以作為拋磚引玉,希望共同討論,指出錯(cuò)誤。

另外,我都是碰到一個(gè)覺(jué)得有必要記錄的問(wèn)題,就寫(xiě)下來(lái)說(shuō)說(shuō),所以每一篇內(nèi)容可能不是單一主題。
1、先來(lái)看一道簡(jiǎn)單題目。有下面這個(gè)繼承類(lèi):
- class Person
- {
- public:
- void Walk() //普通人的“走”
- {
- cout << "Person::Walk I am an Ordinary People." << endl;
- };
- };
- class Student : public Person
- {
- public:
- void Walk() //學(xué)生的“走”
- {
- cout << "Student::Walk I am a student." << endl;
- };
- };
你沒(méi)看錯(cuò)Walk()是非虛函數(shù)。請(qǐng)解釋下面代碼:
- Student s;
- Person* pp = &s;
- pp->Walk();
- Student* ps= &s;
- ps->Walk();
結(jié)果是這樣的:
分析:Walk()是非虛函數(shù),被靜態(tài)綁定所限制,所以pp、ps是什么類(lèi)型就決定了調(diào)用的版本。這里,我還要說(shuō)明的一點(diǎn)是:明白接口繼承和實(shí)現(xiàn)繼承。聲明一個(gè)non-virtual函數(shù)的目的是為了令derived class繼承函數(shù)的接口及一份強(qiáng)制性實(shí)現(xiàn)。所以,絕不要重新定義繼承而來(lái)的non-virtual函數(shù)。
2、下面這個(gè)問(wèn)題實(shí)質(zhì)上也是靜態(tài)綁定與動(dòng)態(tài)綁定的問(wèn)題,但看起來(lái)不那么明顯。
- class Shape
- {
- public:
- enum ShapeColor{Red, Green, Blue}; //形狀顏色
- virtual void Draw(ShapeColor color = Red) const = 0;
- };
- class Circle : public Shape
- {
- public:
- virtual void Draw(ShapeColor color) const
- {
- cout << "I am Circle::Draw. ";
- cout << "My color = " << color << endl;
- }
- };
- class Rectangle : public Shape
- {
- public:
- virtual void Draw(ShapeColor color = Green) const //缺省的參數(shù)值被更改了
- {
- cout << "I am Rectangle::Draw. ";
- cout << "My color = " << color << endl;
- }
- };
我主要想說(shuō)兩個(gè)問(wèn)題。
(1)當(dāng)你下面這樣調(diào)用時(shí),請(qǐng)解釋會(huì)發(fā)生什么情況。
- Circle cr; //(1) 編譯不通過(guò)
- cr.Draw();
- Shape *ps = &cr; //(2)
- ps->Draw();
沒(méi)錯(cuò),(1)通過(guò)對(duì)象調(diào)用而不指定參數(shù)是錯(cuò)誤的,而(2)的結(jié)果是這樣的:color = 0代表Red這你應(yīng)該是知道的。
分析:通過(guò)對(duì)象調(diào)用是靜態(tài)綁定,一定要指定參數(shù)值,因?yàn)殪o態(tài)綁定這個(gè)函數(shù)不從base class繼承缺省參數(shù)值。動(dòng)態(tài)綁定卻可以從base class繼承參數(shù)值。注意,這里我就不強(qiáng)調(diào)動(dòng)態(tài)綁定和靜態(tài)綁定的概念了,但下面這個(gè)一定是靜態(tài)綁定:
- Circle cr;
- Circle *ps = &cr; //這還是靜態(tài)綁定,靜態(tài)類(lèi)型Circle *,編譯不通過(guò)
- ps->Draw();
(2)第二個(gè)我想說(shuō)的問(wèn)題,請(qǐng)解釋下面的調(diào)用結(jié)果。
- Shape* ps1 = new Rectangle;
- ps1->Draw();
- Shape* ps2 = new Circle;
- ps2->Draw();
是這樣令人可喜的結(jié)果:
你是說(shuō),你在Rectangle中已經(jīng)將Draw的缺省值改為1(Green)了,怎么沒(méi)效果?
分析:Rectangle::Draw的缺省參數(shù)值為GREEN,但ps2的靜態(tài)類(lèi)型為Shape*,所以此調(diào)用的缺省參數(shù)值來(lái)自Shape class。
如果你非要讓Rectangle::Draw的參數(shù)有所改變,可以這樣調(diào)用(提供參數(shù)):
- Shape* ps4 = new Rectangle;
- ps4->Draw(Shape::Green);
- Shape* ps5 = new Circle;
- ps5->Draw(Shape::Green);
這個(gè)問(wèn)題是想提醒你:virtual函數(shù)是動(dòng)態(tài)綁定,缺省參數(shù)值是靜態(tài)綁定。所以,不應(yīng)該重新定義這個(gè)缺省參數(shù)值。
3、多重繼承為什么會(huì)含有多個(gè)虛表指針而不是一個(gè)?
這道題是我看一位同學(xué)面試經(jīng)驗(yàn)時(shí),面試官提的,我試著回答一下,不知道在不在點(diǎn)子上,還請(qǐng)補(bǔ)充和指正。
答:多重繼承下,因?yàn)榫幾g器對(duì)一個(gè)derived class實(shí)現(xiàn)了n-1個(gè)虛表,n表示上一層base class的個(gè)數(shù),當(dāng)然假設(shè)每個(gè)base class都有至少有一個(gè)virtual函數(shù),否則編譯器是不會(huì)為其添加vptr和vtbl了。所以說(shuō)有多少個(gè)虛表,自然就有多少個(gè)指針指向,而不是一個(gè)。
這樣說(shuō)我不知道合理不合理,可能面試官要問(wèn)的點(diǎn)是“為什么需要多個(gè)虛表?一個(gè)虛表行不行?”
這個(gè)屬于編譯器廠商做的事情,標(biāo)準(zhǔn)并未規(guī)范。C++的父親就做出過(guò)這樣的一款編譯器原型,通過(guò)增大vtbl的體積,每個(gè)slot上不只有一個(gè)指針,還有一個(gè)offset,用來(lái)調(diào)整this指針的指向。
這樣做的弊端是:所有vtbl中的虛函數(shù)指針都包含這樣一個(gè)offset,并且假設(shè)不需要調(diào)整this指向,調(diào)用時(shí)還是要做offset的加法操作,盡管offset此時(shí)為0。另外,vtbl中每個(gè)slot體積的膨脹。這些都是效率問(wèn)題。
實(shí)際上,用來(lái)調(diào)整this的指向用的比較多的是trunk技術(shù),必須以匯編編寫(xiě)才能獲得高效率。另外,sun編譯器就是把多個(gè)虛表連鎖為1個(gè),每個(gè)表格中含有下一個(gè)表格的指針(通過(guò)offset方式),這樣就需要一個(gè)指針就好了。
理解能力有限,不知道問(wèn)的是不是這么一回事?
新聞名稱(chēng):C++中幾個(gè)值得分析的小問(wèn)題
網(wǎng)頁(yè)URL:http://www.dlmjj.cn/article/dhgjeop.html


咨詢(xún)
建站咨詢(xún)
