?? atl under the hood - part 2.mht
字號:
=
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_2/ATL_2_PIC_1.JPG"=
=20
width=3D276></CENTER>
<P>And when you press Ignore button then it display one more =
dialog=20
<P>
<CENTER><IMG height=3D210=20
=
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_2/ATL_2_PIC_2.JPG"=
=20
width=3D276></CENTER>And in release mode it just displays the =
error message=20
in the output console window. <PRE>In Base
Virtual Pointer =3D 0012FF80
Address of Vtable =3D 0042115C
Value at Vtable 1st entry =3D 0041245D
Value at Vtable 2nd entry =3D 0041245D
runtime error R6025
- pure <SPAN class=3Dcpp-keyword>virtual</SPAN> function call
</PRE>Here what is R6025? It is defined in CMSGS.H file which define all =
error messages used within the C run time library. <PRE><SPAN =
class=3Dcpp-preprocessor>#define _RT_PUREVIRT_TXT "R6025" EOL "- pure =
virtual function call" EOL</SPAN>
</PRE>In fact when we define pure virtual function then compiler place =
the=20
address of one of the C Runtime library function =
<CODE>_purecall</CODE>.=20
This function is define in PUREVIRT.C and have the following =
prototype. <PRE><SPAN class=3Dcpp-keyword>void</SPAN> __cdecl =
_purecall(<SPAN class=3Dcpp-keyword>void</SPAN>)
</PRE>We can achieve the same behavior by directly calling this function =
from our program. Let's take a look at this very small program.=20
<H3>Program 29</H3><PRE><SPAN class=3Dcpp-keyword>int</SPAN> =
main() {
_purecall(); =20
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>The out put of this program is same as previous one in both debug=20
and release mode. To better understand this make the inheritance =
chain=20
deeper and drive one more class from Drive and see the behavior of =
this.=20
<H3>Program 30</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Base() {
cout << <SPAN class=3Dcpp-string>"In Base"</SPAN> << =
endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f1() =3D <SPAN =
class=3Dcpp-literal>0</SPAN>;
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f2() =3D <SPAN =
class=3Dcpp-literal>0</SPAN>;
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Drive() {
cout << <SPAN class=3Dcpp-string>"In Drive"</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> MostDrive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Drive {
<SPAN class=3Dcpp-keyword>public</SPAN>:
MostDrive() {
cout << <SPAN class=3Dcpp-string>"In MostDrive"</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f1() { cout << <SPAN =
class=3Dcpp-string>"MostDrive::f1"</SPAN> << endl; }
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f2() { cout << <SPAN =
class=3Dcpp-string>"MostDrive::f2"</SPAN> << endl; }
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
MostDrive d;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>The output of this program is <PRE>In Base
Virtual Pointer =3D 0012FF7C
Address of Vtable =3D 0046C0D8
Value at Vtable 1st entry =3D 00420F40
Value at Vtable 2nd entry =3D 00420F40
In Drive
Virtual Pointer =3D 0012FF7C
Address of Vtable =3D 0046C0C0
Value at Vtable 1st entry =3D 00420F40
Value at Vtable 2nd entry =3D 00420F40
In MostDrive
Virtual Pointer =3D 0012FF7C
Address of Vtable =3D 0046C0A8
Value at Vtable 1st entry =3D <SPAN class=3Dcpp-literal>00401186</SPAN>
Value at Vtable 2nd entry =3D 004010F5
</PRE>This program shows that both Base and Drive class make their own=20
virtual table and initialized it with the same value. Now what =
happen if=20
the inheritance is further deep and none of the class except the =
most=20
drive overrides any pure virtual function? This happens in the =
case of COM=20
programming where interfaces are class with only pure virtual =
function and=20
one interface is inherited from another interface and only =
implementation=20
class override the pure virtual function of interfaces. Then each =
base=20
class constructor makes their own vtable and put the same value in =
its=20
entry. So it means duplication of same code again and again.=20
<P>The main philosophy of ATL is to make COM component as small as =
possible, but due to this behavior interface class's constructor =
have lot=20
of unnecessary code. To solve this problem ATL introduce a macro=20
<CODE>ATL_NO_VTABLE</CODE> define in ATLDEF.H file as =
</P><PRE><SPAN class=3Dcpp-preprocessor>#define ATL_NO_VTABLE =
__declspec(novtable)</SPAN></PRE>__declspec(novtable)=20
is Microsoft C++ specific extended attribute of class. When it is =
used=20
then compiler won't generate the code to initialize the vptr and =
vtable=20
and reduce the generated code size.=20
<P>Change our program little bit to better understand this what =
this=20
attribute can do for us.=20
<H3>Program 31</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Base() {
cout << <SPAN class=3Dcpp-string>"In Base"</SPAN> << =
endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f1() =3D <SPAN =
class=3Dcpp-literal>0</SPAN>;
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f2() =3D <SPAN =
class=3Dcpp-literal>0</SPAN>;
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Drive() {
cout << <SPAN class=3Dcpp-string>"In Drive"</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> __declspec(novtable) MostDrive : =
<SPAN class=3Dcpp-keyword>public</SPAN> Drive {
<SPAN class=3Dcpp-keyword>public</SPAN>:
MostDrive() {
cout << <SPAN class=3Dcpp-string>"In MostDrive"</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Virtual Pointer =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN> << endl;
cout << <SPAN class=3Dcpp-string>"Address of Vtable =3D =
"</SPAN> << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN class=3Dcpp-keyword>this</SPAN> =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 1st =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>0</SPAN>) =
<< endl;
cout << <SPAN class=3Dcpp-string>"Value at Vtable 2nd =
entry =3D "</SPAN> << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*((<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)<SPAN =
class=3Dcpp-keyword>this</SPAN>+<SPAN class=3Dcpp-literal>1</SPAN>) =
<< endl;
cout << endl;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f1() { cout << <SPAN =
class=3Dcpp-string>"MostDrive::f1"</SPAN> << endl;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -