C C 易錯難點筆記01

2021-07-04 18:16:06 字數 3005 閱讀 9316

c++是一門神奇的語言,很多時候你對底層不熟悉,很難知道某些情況下的結果,下面是我不斷積累的疑惑點,這裡將其記錄下來。

**:

class a

};class b: public a

};int _tmain(int argc, _tchar* argv)

下面語句發生什麼變化。

b* pb = (b*)pa;答:不能覆蓋,派生類重寫基類的虛函式,返回值型別也必須相同。

如下**報錯嗎?

class a

};class b: public a

};

解釋,在基類沒有預設構造的情況下,派生類是需要顯式呼叫。所以上面**編譯不通過。

下面程式結果是什麼:

class a;

class b;

class c:public a,public b;

int _tmain(int argc, _tchar* argv)

解析:每個語句解釋如下,

1.a* pa = dynamic_cast(pc);此時pa指向了子類a的那部分,位址值與pc相同。

2.b pbb = *pc;這裡會發生切割,呼叫了b類拷貝構造,將b的那部分切割到pbb的所在的棧空間中。

3.if (pc == pb)這裡會發生隱式型別轉換,pc = (c*)pb

4.if ((int)pc == (int)pa)雖然沒有隱式型別轉換,但位址相同。

下面**中哪條語句會出現問題。

class a

void pp()

};class b:public a

void pp()

void funb()

};int _tmain(int argc, _tchar* argv)

解析:語句1會出現問題。foo()是虛函式,編譯器會根據物件的虛函式指標查詢虛函式表,定位foo函式。

dynamic_cast不是強制型別轉換,而是帶有某種「諮詢」性質的,如果不能轉換,dynamic_cast會返回null,表示不成功。

上面3條語句相當於:

b* bnull =

null;

bnull->foo();

bnull->pp();

bnull->funb();

上面的轉換時不成功的,所以返回的是null指標,又因為pp和funb函式未使用任何成員資料,也不是虛函式,不需要this指標,也不需要動態繫結,所以可以正常執行。

下面**輸出結果是多少?

class a;

private:

char ca[3];

};class b:virtual

public a;

private:

char cb[3];

};class c:virtual

public b;

private:

char cb[3];

};int _tmain(int argc, _tchar* argv)

解析:結果是8,16,24。

然而,下面**輸出結果又是多少?

去掉了虛擬繼承

class a;

private:

char ca[3];

};class b:public a;

private:

char cb[3];

};class c:public b;

private:

char cb[3];

};int _tmain(int argc, _tchar* argv)

解析:結果為8,12,6。

1.帶有虛函式的虛擬繼承中,也分兩種情況,1.派生類中定義了新的虛函式,並且部分重寫了虛基類的虛函式,這個時候,派生類中有3個虛表指標,乙個指向虛基類的虛函式指標,乙個自己的虛表指標(實現多型),還有乙個基類自己虛表指標。2.派生類全部重寫虛基類虛函式,且沒有新定義虛函式,這時候,派生類中含有兩個虛表指標,還有乙個基類自己虛表指標,個指向虛基類的虛函式指標。

2.基類不帶虛函式的虛繼承中,分兩種情況,1.基類和派生類中都沒有虛函式,這個時候,派生類只會多新增乙個虛表指標,指向虛基類的虛函式(雖然虛基類中沒有虛函式)。2.基類中沒有虛函式,派生類中有虛函式,則會生產兩個虛表指標,乙個指向自己虛函式的的虛表指標和乙個指向虛基類的虛函式指標

3.帶虛函式的普通繼承中,這個時候不論是基類還是派生類,只要類中有虛函式,都會有且只有乙個虛函式指標。

再看下面**:

驗證了第乙個的第一種情況。

在看下面:

這驗證了第二個的第二種情況。

還有乙個很有趣的問題:

怎麼沒有記憶體對其了呢?這時如果再定義乙個int就會有記憶體對齊了。如果沒有就是以1位元組對齊。

最後,總結下,虛擬繼承和虛函式多型機制是分開的,虛擬繼承會保留基類中的虛表指標,並且新增乙個指向虛基類的虛擬指標,它並不會實現多型。

指標難點 易錯點

voidf char c intmain f c 這裡的f char c 指向指標的指標 所以呼叫時一定要 使用指標 c 3 定義指標陣列 c 第乙個指標變數的位址。指標的位址 用指向指標的指標存放 二 例如 int a 3 4 ptr2是乙個指向 int 的指標,即ptr2的型別和 ptr是一樣的...

C C 易錯總結

一 分析如下 char tostr int num s i 0 return s 本意為將整數轉化成字元陣列儲存,然後將這個字元陣列返回。經艱苦實踐,發現不能,原因是指標s是區域性變數,當函式返回時s即銷毀,當然不會返回成功了,只能把乙個無意義的位址傳回去。所以正確的處理方法可以這樣。void to...

C C 易錯問題分析

傳給函式形參的實參是作為拷貝傳入,在函式體內改變作為拷貝的實參2是不會影響到傳入的實參1的。規則 1 如果想要通過函式介面改變傳入的數值,那麼需要傳入該數值的指標。2 如果想要改變傳入的指標所指向的值,那麼需要傳入該指標的指標。總之,需要深一層。int fun int fun1 修改方法 由上層呼叫...