📄 atl under the hood - part 1.mht
字号:
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
CPoint objPoint;
cout << "Size of Class =3D " << <SPAN =
class=3Dcpp-keyword>sizeof</SPAN>(objPoint) << endl;
cout << "Address of Class =3D " << &objPoint << =
endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is </P><PRE>Size of Class =3D <SPAN =
class=3Dcpp-literal>12</SPAN>
Address of Class =3D 0012FF68</PRE>
<P>The output of these programs shows that when you add any =
virtual=20
function in the class then its size increases one <CODE><SPAN=20
class=3Dcpp-keyword>int</SPAN></CODE> size. i.e. in Visual C++ it =
increase=20
by 4 bytes. It means there are 3 slots for integer in this class =
one for x=20
one for y and one to handle virtual function that is called a =
virtual=20
pointer. First take a look at the new slot, namely the virtual =
pointer=20
that is at the start (or end) the object. To do this we are going =
to=20
directly access memory occupied by the object. We do this by =
storing the=20
address of an object in an <CODE><SPAN =
class=3Dcpp-keyword>int</SPAN></CODE>=20
pointer and using the magic of pointer arithmetic.=20
<H3>Program 7.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> CPoint {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>int</SPAN> m_ix;
<SPAN class=3Dcpp-keyword>int</SPAN> m_iy;
CPoint(<SPAN class=3Dcpp-keyword>const</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN> p_ix =3D <SPAN =
class=3Dcpp-literal>0</SPAN>, <SPAN class=3Dcpp-keyword>const</SPAN> =
<SPAN class=3Dcpp-keyword>int</SPAN> p_iy =3D <SPAN =
class=3Dcpp-literal>0</SPAN>) :=20
m_ix(p_ix), m_iy(p_iy) {=20
}
<SPAN class=3Dcpp-keyword>int</SPAN> getX() <SPAN =
class=3Dcpp-keyword>const</SPAN> {
<SPAN class=3Dcpp-keyword>return</SPAN> m_ix;
}
<SPAN class=3Dcpp-keyword>int</SPAN> getY() <SPAN =
class=3Dcpp-keyword>const</SPAN> {
<SPAN class=3Dcpp-keyword>return</SPAN> m_iy;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> ~CPoint() { };
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
CPoint objPoint(<SPAN class=3Dcpp-literal>5</SPAN>, <SPAN =
class=3Dcpp-literal>10</SPAN>);
<SPAN class=3Dcpp-keyword>int</SPAN>* pInt =3D (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)&objPoint;
*(pInt+<SPAN class=3Dcpp-literal>0</SPAN>) =3D <SPAN =
class=3Dcpp-literal>100</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of x</SPAN>
*(pInt+<SPAN class=3Dcpp-literal>1</SPAN>) =3D <SPAN =
class=3Dcpp-literal>200</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of y</SPAN>
cout << "X =3D " << objPoint.getX() << endl;
cout << "Y =3D " << objPoint.getY() << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The important thing in this program is </P><PRE> <SPAN =
class=3Dcpp-keyword>int</SPAN>* pInt =3D (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)&objPoint;
*(pInt+<SPAN class=3Dcpp-literal>0</SPAN>) =3D <SPAN =
class=3Dcpp-literal>100</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of x</SPAN>
*(pInt+<SPAN class=3Dcpp-literal>1</SPAN>) =3D <SPAN =
class=3Dcpp-literal>200</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of y</SPAN>
</PRE>In which we treat object as an integer pointer after store its=20
address in integer pointer. The output of this program is <PRE>X =
=3D <SPAN class=3Dcpp-literal>200</SPAN>
Y =3D <SPAN class=3Dcpp-literal>10</SPAN>
</PRE>
<P>Of course this is not our required result. This shows when 200 =
is store=20
in the location where <CODE>m_ix</CODE> data member is resident. =
This=20
means <CODE>m_ix</CODE> i.e. first member variable, start from =
second=20
position of the memory not the first. In other words the first =
member is=20
the virtual pointer and then rest is the data member of the =
object. Just=20
change the following two lines</P><PRE><SPAN =
class=3Dcpp-keyword>int</SPAN>* pInt =3D (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)&objPoint;
*(pInt+<SPAN class=3Dcpp-literal>1</SPAN>) =3D <SPAN =
class=3Dcpp-literal>100</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of x</SPAN>
*(pInt+<SPAN class=3Dcpp-literal>2</SPAN>) =3D <SPAN =
class=3Dcpp-literal>200</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of y</SPAN>
</PRE>
<P>And we get the required result. Here is the complete program=20
<H3>Program 8.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> CPoint {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>int</SPAN> m_ix;
<SPAN class=3Dcpp-keyword>int</SPAN> m_iy;
CPoint(<SPAN class=3Dcpp-keyword>const</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN> p_ix =3D <SPAN =
class=3Dcpp-literal>0</SPAN>, <SPAN class=3Dcpp-keyword>const</SPAN> =
<SPAN class=3Dcpp-keyword>int</SPAN> p_iy =3D <SPAN =
class=3Dcpp-literal>0</SPAN>) :=20
m_ix(p_ix), m_iy(p_iy) {=20
}
<SPAN class=3Dcpp-keyword>int</SPAN> getX() <SPAN =
class=3Dcpp-keyword>const</SPAN> {
<SPAN class=3Dcpp-keyword>return</SPAN> m_ix;
}
<SPAN class=3Dcpp-keyword>int</SPAN> getY() <SPAN =
class=3Dcpp-keyword>const</SPAN> {
<SPAN class=3Dcpp-keyword>return</SPAN> m_iy;
}
<SPAN class=3Dcpp-keyword>virtual</SPAN> ~CPoint() { };
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
CPoint objPoint(<SPAN class=3Dcpp-literal>5</SPAN>, <SPAN =
class=3Dcpp-literal>10</SPAN>);
<SPAN class=3Dcpp-keyword>int</SPAN>* pInt =3D (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)&objPoint;
*(pInt+<SPAN class=3Dcpp-literal>1</SPAN>) =3D <SPAN =
class=3Dcpp-literal>100</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of x</SPAN>
*(pInt+<SPAN class=3Dcpp-literal>2</SPAN>) =3D <SPAN =
class=3Dcpp-literal>200</SPAN>; <SPAN class=3Dcpp-comment>// want to =
change the value of y</SPAN>
cout << "X =3D " << objPoint.getX() << endl;
cout << "Y =3D " << objPoint.getY() << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>And output of the program is </P><PRE>X =3D <SPAN =
class=3Dcpp-literal>100</SPAN>
Y =3D <SPAN class=3Dcpp-literal>200</SPAN>
</PRE>
<P>This clearly shows that whenever we add the virtual function =
into the=20
class then the virtual pointer is added at first location of =
memory=20
structure.=20
<P>
<CENTER><IMG height=3D289=20
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_/CPP1.GIF"=20
width=3D317></CENTER><BR>Now the question arises: what is stored =
in the=20
virtual pointer? Take a look at the following program to get an =
idea of=20
this
<P></P>
<H3>Program 9.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Class {
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> fun() { cout << "Class::fun" =
<< endl; }
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Class objClass;
cout << "Address of <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer " << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
cout << "Value at <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer " << (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is </P><PRE>Address of <SPAN =
class=3Dcpp-keyword>virtual</SPAN> pointer 0012FF7C
Value at <SPAN class=3Dcpp-keyword>virtual</SPAN> pointer 0046C060
</PRE>
<P>The virtual pointer stores the address of a table that is =
called the=20
virtual table. And a virtual table stores address of all the =
virtual=20
functions of that class. In other words the virtual table is an =
array of=20
addresses of virtual functions. Let's take a look at the following =
program=20
to get an idea of it.=20
<H3>Program 10.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Class {
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> fun() { cout << "Class::fun" =
<< endl; }
};
<SPAN class=3Dcpp-keyword>typedef</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> (*Fun)(<SPAN =
class=3Dcpp-keyword>void</SPAN>);
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Class objClass;
cout << "Address of <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer " << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
cout << "Value at <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer i.e. Address of <SPAN class=3Dcpp-keyword>virtual</SPAN> table " =
<< (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
cout << "Value at first entry of <SPAN =
class=3Dcpp-keyword>virtual</SPAN> table "=20
<< (<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
cout << endl << "Executing <SPAN =
class=3Dcpp-keyword>virtual</SPAN> function" << endl << =
endl;
Fun pFun =3D (Fun)*(<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>);
pFun();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>This program has some uncommon indirection with typecast. The =
most=20
important line of this program is </P><PRE> Fun pFun =3D =
(Fun)*(<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>);
</PRE>Here <CODE>Fun </CODE>is a <CODE><SPAN=20
class=3Dcpp-keyword>typedef</SPAN></CODE>'d function pointer. =
<PRE> <SPAN class=3Dcpp-keyword>typedef</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> (*Fun)(<SPAN =
class=3Dcpp-keyword>void</SPAN>);
</PRE>
<P>Let's dissect the lengthy uncommon indirection. <CODE>(<SPAN=20
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN=20
class=3Dcpp-literal>0</SPAN>) </CODE>gives the address of the =
virtual=20
pointer of the class which is the first entry in the class and we =
typecast=20
it to <CODE><SPAN class=3Dcpp-keyword>int</SPAN>*</CODE>. To get =
the value=20
at this address we use the indirection operator (i.e. =
<CODE>*</CODE>) and=20
then again typecast it to <CODE><SPAN =
class=3Dcpp-keyword>int</SPAN>*</CODE>=20
i.e. <CODE>(<SPAN class=3Dcpp-keyword>int</SPAN>*)*(<SPAN=20
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN=20
class=3Dcpp-literal>0</SPAN>)</CODE>. This will give the address =
of first=20
entry of the virtual table. To get the value at this location, =
i.e. get=20
the address of first virtual function of the class again use the=20
indirection operator and now typecast to the appropriate function =
pointer=20
type. So </P><PRE> Fun pFun =3D (Fun)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)*(<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>);</PRE>
<P>Means get the value from the first entry of the virtual table =
and store=20
it in pFun after typecast it into the Fun type.=20
<CENTER><IMG height=3D92=20
src=3D"http://www.codeproject.com/atl/ATL_UnderTheHood_/CPP2.GIF"=20
width=3D400></CENTER><BR>What happen when one more virtual =
function add in=20
the class. Now we want to access second member of the virtual =
table. Take=20
a look at the following program to see the values at virtual table =
<H3>Program 11.</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Class {
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> f() { cout << "Class::f" << =
endl; }
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> g() { cout << "Class::g" << =
endl; }
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Class objClass;
cout << "Address of <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer " << (<SPAN =
class=3Dcpp-keyword>int</SPAN>*)(&objClass+<SPAN =
class=3Dcpp-literal>0</SPAN>) << endl;
cout << "Value at <SPAN class=3Dcpp-keyword>virtual</SPAN> =
pointer i.e. Address of <SPAN class=3Dcpp-keyword>virtual</SPAN> table " =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -