![](/img/trans.png)
[英]Another BUG of VC++ 2010? About declaring a constant REFERENCE in a header
[英]Is this a bug in VC++ 2010?
當我在C ++中嘗試鑽石問題時遇到了這個問題。 以下程序對我而言在Visual Studio 2010中有效,並且得到以下輸出。
D
D
A
A
B
Error7
C
C
5
7
7
Press any key to continue . . .
如果您有任何解釋,請向我解釋。
注意,任何B對象都絕不會以任何方式構造。 大多數派生類D僅從C和A派生。 不是B。我想知道m_i2從哪里獲得值7?
#include "stdafx.h"
#include <iostream>
using namespace std;
class A{ int m_i1;
public:
A(int i1){ m_i1 = i1;}
int GetMI1(){ return m_i1;}
void printABCD(){cout << "A" << endl;}
};
class B : public A {
int m_i2;
public:
B(int i1):A(i1){}
void printABCD(){cout << "B" << endl;}
void printEFGH(){cout << "Error" << m_i2 << endl;}
};
class C : virtual public A{
public:
C(int i1):A(i1){}
void printABCD(){cout << "C" << endl;}
};
class D : public C, public virtual A{
public:
D(int i1):C(i1+1),A(i1){}
void printABCD(){cout << "D" << endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a(5); D d(7); C c(7); D* e = new D(7);
d.printABCD();
e->printABCD();
((A)d).printABCD();
((A*)e)->printABCD();
((B*)e)->printABCD();
((B*)e)->printEFGH(); // This line works perfectly, but why??
//((B)(d)).printABCD(); //This will error and its right
((C*)e)->printABCD();
((C)d).printABCD();
cout << a.GetMI1() << endl;
cout << c.GetMI1() << endl;
cout << d.GetMI1() << endl;
system("pause");
return 0;
}
Undefined behaviour is undefined.
解除引用(B*)e
的那一刻,您的程序就具有未定義的行為(因為e
實際上並未指向B
對象),因此任何事情都可能發生。 該程序似乎可以運行,可能會崩潰,可以在線訂購披薩。
對該行為的一種可能解釋可能是D
的布局恰好使得C
子對象位於內存中的首位,並且具有與int
相同的大小(它可能僅包含指向虛擬基數A
的指針),並且其后是A
子對象的成員m_i1
與D
對象起點的偏移量與成員m_i2
與B
對象起點的偏移量相同。 因此,代碼在執行B::printEFGH()
時A::m_i1
解釋為B::m_i2
。 但這純粹是猜測。 與任何UB一樣,幾乎任何事情都可能發生。
編譯器正在生成的代碼完全可以執行您所要執行的操作(並且您正在“告訴”它以調用未定義的行為)。 該函數調用你是不是虛擬的,因此有編譯器可以(而且會)生成代碼,只需按下this
到堆棧並調用一個成員函數,字面上的call
,而不需要vtable
的分辨率。
這是完全不確定的行為 ,我希望這很清楚,所以不要這樣做。 您獲得的值是發生在與要傳遞的對象的基址偏移的內存中的任何值( 不是 B派生)。
如果您想看到一些奇怪的東西(同樣是UB)。 在class D
添加一個int
成員m_dval
,然后在D結構上將其設置為42,然后UB是否完全按照您的要求進行調用。 我認為這可能會讓您感到驚訝,因為m_i2
成員值(不是,btw)被報告m_i2
。
首先,您的代碼包含行為未定義的無效調用。
D
類的祖先中沒有B
類。 這意味着從D *
到B *
任何強制轉換以及隨后使用結果指針指向B
類型對象的任何嘗試均已無效。 如果您使用C ++樣式的static_cast
( static_cast
),則編譯器會告訴您有關它的信息(就像它對(B)(d)
嘗試所做的那樣)。 嘗試分析此類轉換后執行的任何調用沒有任何意義。 即這個
((B*)e)->printABCD();
((B*)e)->printEFGH();
具有未定義的行為。
其次,您說您正在“用C ++進行鑽石問題的實驗”。 您的代碼中與“鑽石問題”有關的唯一部分實際上是此調用
cout << d.GetMI1() << endl;
它顯示了D(7) -> A(7)
初始值設定項勝過D(7) -> C(8) -> A(8)
初始值設定項。 其余的調用與任何“鑽石”效果完全無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.