📄 atl under the hood - part 1.mht
字号:
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is </P><PRE>Base1::f
Base1::g
Base2::f
Base2::f
Base3::f
Base3::f
Drive::fd
Drive::gd
</PRE>
<P>This program show that the virtual function of drive store in =
the=20
vtable of first vptr.=20
<P>
<CENTER><IMG height=3D277=20
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_/CPP6.GIF"=20
width=3D400></CENTER><BR>We can get the offset of Drive class vptr =
with the=20
help of <CODE><SPAN class=3Dcpp-keyword>static_cast</SPAN></CODE>. =
Let's=20
take a look at he following program to better understand it.
<P></P>
<H3>Program 16.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base1 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base2 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base3 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base1, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base2, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base3 {
};
<SPAN class=3Dcpp-comment>// any non zero value because multiply zero =
with any no is zero</SPAN>
<SPAN class=3Dcpp-preprocessor>#define SOME_VALUE 1</SPAN>
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
cout << (DWORD)<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><Base1*>((Drive*)SOME_VALUE)-=
SOME_VALUE << endl;
cout << (DWORD)<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><Base2*>((Drive*)SOME_VALUE)-=
SOME_VALUE << endl;
cout << (DWORD)<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><Base3*>((Drive*)SOME_VALUE)-=
SOME_VALUE << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>ATL use a macro name offsetofclass defined in ATLDEF.H to do =
this.=20
Macro is defined at </P><PRE><SPAN =
class=3Dcpp-preprocessor>#define offsetofclass(base, derived) \</SPAN>
((DWORD)(<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><base*>((derived*)_ATL_PACKIN=
G))-_ATL_PACKING)
</PRE>
<P>This macro returns the offset of the base class vptr in the =
drive class=20
object model. Let's see an example to get an idea of this=20
<H3>Program 17.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<windows.h></SPAN>
<SPAN class=3Dcpp-preprocessor>#include <iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base1 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base2 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base3 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base1, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base2, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base3 {
};
<SPAN class=3Dcpp-preprocessor>#define _ATL_PACKING 8</SPAN>
<SPAN class=3Dcpp-preprocessor>#define offsetofclass(base, derived) =
\</SPAN>
((DWORD)(<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><base*>((derived*)_ATL_PACKIN=
G))-_ATL_PACKING)
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
cout << offsetofclass(Base1, Drive) << endl;
cout << offsetofclass(Base2, Drive) << endl;
cout << offsetofclass(Base3, Drive) << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The memory layout of the drive class is=20
<CENTER><IMG height=3D145=20
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_/CPP5.GIF"=20
width=3D241></CENTER><BR>And output of this program is <PRE><SPAN =
class=3Dcpp-literal>0</SPAN>
<SPAN class=3Dcpp-literal>4</SPAN>
<SPAN class=3Dcpp-literal>8</SPAN>
</PRE>
<P>Output of this program shows this macro returns the offset of =
vptr of=20
the required base class. In Don Box's Essential COM, he used a =
similar=20
macro to this. Change the program little bit and replace ATL macro =
with=20
Box's macro.=20
<H3>Program 18.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<windows.h></SPAN>
<SPAN class=3Dcpp-preprocessor>#include <iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base1 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base2 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base3 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base1, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base2, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base3 {
};
<SPAN class=3Dcpp-preprocessor>#define BASE_OFFSET(ClassName, BaseName) =
\</SPAN>
(DWORD(<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><BaseName*>(<SPAN =
class=3Dcpp-keyword>reinterpret_cast</SPAN><ClassName*>\
(<SPAN class=3Dcpp-literal>0x10000000</SPAN>))) - <SPAN =
class=3Dcpp-literal>0x10000000</SPAN>)
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
cout << BASE_OFFSET(Drive, Base1) << endl;
cout << BASE_OFFSET(Drive, Base2) << endl;
cout << BASE_OFFSET(Drive, Base3) << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output and purpose of this program is the same as the =
previous=20
program.=20
<P>Let's do something practical and use this macro in our program. =
In fact=20
we can call the virtual function of our required base class by =
getting the=20
offset of base class vptr in drive's memory structure.</P>
<H3>Program 19.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<windows.h></SPAN>
<SPAN class=3Dcpp-preprocessor>#include <iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Base1 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { cout << "Base1::f()" =
<< endl; }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base2 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { cout << "Base2::f()" =
<< endl; }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base3 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { cout << "Base3::f()" =
<< endl; }
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base1, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base2, <SPAN =
class=3Dcpp-keyword>public</SPAN> Base3 {
};
<SPAN class=3Dcpp-preprocessor>#define _ATL_PACKING 8</SPAN>
<SPAN class=3Dcpp-preprocessor>#define offsetofclass(base, derived) =
\</SPAN>
((DWORD)(<SPAN =
class=3Dcpp-keyword>static_cast</SPAN><base*>((derived*)_ATL_PACKIN=
G))-_ATL_PACKING)
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Drive d;
<SPAN class=3Dcpp-keyword>void</SPAN>* pVoid =3D NULL;
<SPAN class=3Dcpp-comment>// call function of Base1</SPAN>
pVoid =3D (<SPAN class=3Dcpp-keyword>char</SPAN>*)&d + =
offsetofclass(Base1, Drive);
((Base1*)(pVoid))->f();
<SPAN class=3Dcpp-comment>// call function of Base2</SPAN>
pVoid =3D (<SPAN class=3Dcpp-keyword>char</SPAN>*)&d + =
offsetofclass(Base2, Drive);
((Base2*)(pVoid))->f();
<SPAN class=3Dcpp-comment>// call function of Base1</SPAN>
pVoid =3D (<SPAN class=3Dcpp-keyword>char</SPAN>*)&d + =
offsetofclass(Base3, Drive);
((Base3*)(pVoid))->f();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is </P><PRE>Base1::f()
Base2::f()
Base3::f()
</PRE>
<P>I tried to explain the working of <CODE>offsetofclass</CODE> =
macro of=20
ATL in this tutorial. I Hope to explore other mysterious of ATL in =
the=20
next article. <!-- Article Ends --></P></DIV>
<H2>About Zeeshan Amjad</H2>
<TABLE width=3D"100%" border=3D0>
<TBODY>
<TR vAlign=3Dtop>
<TD class=3DsmallText noWrap><BR></TD>
<TD class=3DsmallText width=3D"100%">Software Engineer at =
SoftPak=20
Financial Systems<BR><A=20
=
href=3D"http://www.softpak.com/">http://www.softpak.com/</A><BR><BR>And=20
sometimes teaching Object Oriented programming and C++ in =
University=20
of Karachi as a Visiting Faculty Member.<BR><A=20
href=3D"http://www.csku.edu.pk/">http://www.csku.edu.pk/</A>
<P class=3DsmallText>Click <A=20
=
href=3D"http://www.codeproject.com/script/profile/whos_who.asp?vt=3Darts&=
amp;id=3D5890">here</A>=20
to view Zeeshan Amjad's online =
profile.</P></TD></TR></TBODY></TABLE><BR>
<H2>Other popular ATL articles:</H2>
<UL>
<LI><A=20
=
href=3D"http://www.codeproject.com/atl/shellfoldertree.asp">ShellFolderTr=
ee</A><BR><SPAN=20
class=3Dsmalltext>Mimicking and extending the shell=92s =
folder-tree control=20
functionality</SPAN>
<LI><A href=3D"http://www.codeproject.com/atl/atlserver.asp">ATL =
Server -=20
Web Application/Web Service</A><BR><SPAN class=3Dsmalltext>Web=20
Application/Web Service development using ATL Server =
classes</SPAN>
<LI><A =
href=3D"http://www.codeproject.com/atl/newinatl7.asp">What's new in=20
ATL7</A><BR><SPAN class=3Dsmalltext>Overview of new classes in =
ATL7</SPAN>
<LI><A=20
=
href=3D"http://www.codeproject.com/atl/ietoolbartutorial.asp">Internet=20
Explorer Toolbar (Deskband) Tutorial</A><BR><SPAN =
class=3Dsmalltext>A=20
tutorial on Using RBDeskband and CWindowImpl ATL Object Wizards =
to=20
create an Internet Explorer(IE) Toolbar.</SPAN></LI></UL>
<FORM action=3D/script/rating/code/app/insert_vote.asp =
method=3Dpost><INPUT=20
type=3Dhidden value=3D/atl/ATL_UnderTheHood_.asp-1/28/2002 =
name=3Dvote_name>=20
<INPUT type=3Dhidden value=3D/atl/atl_underthehood_.asp =
name=3Dgoal>=20
<TABLE cellSpacing=3D0 cellPadding=3D1 width=3D"100%" =
bgColor=3D#ff9900=20
border=3D0><TBODY>
<TR>
<TD width=3D"100%">
<TABLE cellSpacing=3D0 cellPadding=3D4 width=3D"100%" =
bgColor=3D#fbedbb=20
border=3D0>
<TBODY>
<TR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -