C 必知必會(3)

2022-09-24 01:48:09 字數 3247 閱讀 8769

class x

public:

xoperator %( const x& ) const; //二元取餘操作

xmemfunc1( const x&);

voidmemfunc2();

可以採用中綴或函式呼叫語法來呼叫這個過載的操作符:如下

x a,b,c;

a = b%c; //採用中綴語法呼叫成員操作符%

a = b.operator %(c); //成員函式呼叫語法

a = b.memfunc1(c); //另乙個成員函式呼叫

然而,對重重愛操作符中的中綴呼叫的處理機制與此不同:

x operaator %(const x &, int); //非成員操作符宣告

void x::memfunc2()

*this% 12; //呼叫非成員操作符%

operator%(*this, 12); //錯誤!實參太多

第乙個對operator %的中綴呼叫,將會匹配非成員的那乙個。這不是乙個過載的例子,而是編譯器在兩個不同的地方查詢候選函式。第二個對operator %的非中綴呼叫准許標準的函式查詢規則,因而匹配那個成員函式,但是這裡我們會遇到乙個錯誤,因為我們試圖將三個實參傳遞給乙個二元函式。(記住,對成員函式的呼叫存在乙個隱式的實參this!)

能力查詢通常是通過對不相關的型別進行dynamic_cast轉換而表達的。

class shape;

class subject;

class observedblob : public shape,public subject

;int main()

執行結果如下:

3759208

3759208

3759212

subj = ob

subj = v

ob != v

請按任意鍵繼續. . .

由於ob,s,subj都指向同乙個物件,因此編譯器必須區別ob與s和subj的比較結果均為true。編譯器通過將參與比較的指著值之一調整一定的偏移量來完成這種比較。例如,表示式:

ob == subj;

可能被轉化翻譯為

ob ? (ob+delta ==ubj) : (subj == 0)

所以本例結果為ob =subj。

但一般而言,當我們處理指向物件的指標或引用時,必須小心避免丟失型別資訊。指向void的指標是常見的錯誤。如上,一旦通過將物件的指標複製到void*將會去掉物件中包含的位址型別資訊,編譯器別無他法,只好求助於原始位址比較。所以才會出現以上結果。

subj = v

ob != v

在點餐時,想點乙份別人再吃的事物,可用如下程式實現:

class meal;

class spaghetti : publicmeal };

constmeal* m = thatguymeal(); //不管他正在吃什麼

meal*mymeal = m->clone(); //我都要乙份和他一樣的!

事實上,我們完全有可能所點的事務沒有一點了解。

這裡實際上使用了prototype模式,對乙個型別的存在不知情並不會對建立該型別的物件造成任何障礙。

而所謂的虛建構函式,並不是真正的虛建構函式,但是生成物件的乙份複製品通常涉及到通過對乙個虛函式對其類的建構函式的間接呼叫,效果上也算得上是虛建構函式了。

factory method的本質在於,基類提供乙個虛函式掛鉤,用於產生適當的產品。每乙個派生類可以重寫繼承的虛函式,為自己產生適當的產品。實際上,我們具備了使用乙個位置型別的物件來產生另乙個未知型別物件的能力。

一般來說,乙個重寫的函式必須與被它重寫的函式具有相同的返回型別。

但是,這個規則對於「協變返回型別」不嚴格。也就說,如果b是乙個類型別,並且乙個基類虛函式返回b*,那麼乙個重寫的派生類函式可以返回d*,其中的d公有派生於b。如果基類虛函式返回b&,那麼乙個重寫的派生類函式可以返回乙個d&。

可以通過將複製操作(複製建構函式和複製賦值函式)宣告為private同時不為之提供定義而做到。

抽象基類用於目標問題領域的抽象概念,建立這種型別的喜愛那個是沒有什麼意義的。我們通過至少宣告乙個純虛函式使得乙個基類成為抽象的,編譯器將會確保無人能夠建立該抽象基類的任何物件。例如:

class abc

注意,在這個例子中,很有必要為該純虛函式提供乙個實現,因為派生類的析構函式將會隱式地呼叫其基類的析構函式(注意,從乙個派生類析構函式內部對乙個基類析構函式的隱式呼叫,總是非虛擬的)。

方法3:受保護的析構函式和受保護的建構函式發揮的效果基本相同,不過前者的報錯發生於物件離開作用域時或被顯示銷毀時,而不是在物件建立時。

class abc

void operator delete(void*){}

任何在堆上分配乙個noheap物件的習慣性嘗試,都會產生編譯器錯誤。

noheap * nh =new noheap; //錯誤!noheap::operatornew是受保護的

delete nh; //錯誤!noheap::operatordelete是受保護的

之所以給出operator new和operator的定義,是因為在一些平台上它們可能會被構造和析構函式呼叫。處於同樣原因,我們將其宣告為protected是因為它們可能被派生類的建構函式和析構函式隱式的呼叫。如果noheap不打算用作基類,那麼這兩個函式也可以宣告為private。

同時,還要注意阻止堆上分配noheap物件的陣列。在這種情況下,只要將array new和array delete宣告為private且不予定義即可,類似於禁止複製操作的方式。

class noheap

void operatoe delete(void*){}

private:

void* operator new(size_t);

void operator delete(void*);

當然,在某些場合下,我們可能鼓勵使用對分配,只需要將析構函式宣告為private即可。

class onheap{

~onheap();

public:

void destroy()

delete this;

當物件的名字離開其作用域時,任何乙個宣告自動或靜態onheap物件的嘗試,都會產生乙個隱式的析構函式呼叫:

onheap oh1; //錯誤!隱式呼叫私有析構函式

void afunc()

onheap oh2;

//錯誤!隱式呼叫oh2析構函式

C 必知必會

條款2 多型 2 條款3 設計模式 5 條款4 stl 8 條款5 引用是別名而非指標 10 條款6 陣列形參 13 條款7 常量指標與指向常量的指標 16 條款8 指向指標的指標 19 條款9 新式轉型操作符 21 條款10 常量成員函式的含義 25 條款11 編譯器會在類中放東西 29 條款12...

mysql 必知必會 3

排序檢索資料 1.排序資料 order 排序 乙個列或多個列,進行排序輸出 select 列名 from 表名 order by 列名 多列排序 先列名1排序,再列名2排序 select 列名1,列名2 from 表名 order by 列名1,列名2 指定排序的方向。資料排序預設是公升序排序,降序...

C 必知必會(3)設計模式

c 設計模式 對 於任何還不熟悉設計模式的人來說,在對這個領域進行簡短的縱覽之後,可能會留下這樣的印象 設計模式是乙個市場營銷大 它不過是一些簡單的程式設計技術,或者不過是計算機科學家 這些科學家沒事應該多出來走走 的玩物。儘管這些印象都有那麼一點道理,然而設計模式的確是職業 c 程式設計師工具箱中...