📄 atl under the hood - part 3.mht
字号:
obj1.Play();
obj2.Play();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>Here Round1 and Round2 are classes of different round of a game =
and=20
Strategy class decide what do to do depend on the template =
parameter pass=20
to this class.</P>
<P>The output of the program is</P><PRE lang=3Dtext>Round1::Play
Round2::Play</PRE>
<P>ATL implement threading using Strategy design pattern.</P>
<P>Proxy design pattern can also be implemented using template. =
Smart=20
pointer is an example of proxy design pattern. Here is an example =
of=20
simplified version of smart pointer without using template.</P>
<H3>Program 46</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Inner {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> Fun() {
cout << "Inner::Fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> Outer {
<SPAN class=3Dcpp-keyword>private</SPAN>:
Inner* m_pInner;
<SPAN class=3Dcpp-keyword>public</SPAN>:
Outer(Inner* p_pInner) : m_pInner(p_pInner) {
}
Inner* <SPAN class=3Dcpp-keyword>operator</SPAN> -> () {
<SPAN class=3Dcpp-keyword>return</SPAN> m_pInner;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Inner objInner;
Outer objOuter(&objInner);
objOuter->Fun();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is</P><PRE =
lang=3Dtext>Inner::Fun()</PRE>
<P>For simplicity, we just overload the -> operator, but in =
real smart=20
pointer all the necessary operators such as =3D, =3D=3D, !, &, =
* are=20
overloaded. There is one big problem with this smart pointer; this =
can=20
only contain pointer to Inner object. We can remove this =
restriction by=20
making OuterClass template. Let's change program little bit.</P>
<H3>Program 47</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>class</SPAN> Inner {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> Fun() {
cout << "Inner::Fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>typename</SPAN> T>
<SPAN class=3Dcpp-keyword>class</SPAN> Outer {
<SPAN class=3Dcpp-keyword>private</SPAN>:
T* m_pInner;
<SPAN class=3Dcpp-keyword>public</SPAN>:
Outer(T* p_pInner) : m_pInner(p_pInner) {
}
T* <SPAN class=3Dcpp-keyword>operator</SPAN> -> () {
<SPAN class=3Dcpp-keyword>return</SPAN> m_pInner;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Inner objInner;
Outer<Inner> objOuter(&objInner);
objOuter->Fun();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is same as previous one but now =
OuterClass=20
can contain any class whose type is passed as a template =
parameter.</P>
<P>ATL has two smart pointer classes. <CODE>CComPtr</CODE> and=20
<CODE>CComQIPtr</CODE>.</P>
<P>You can do some interesting work with the help of template. =
E.g. your=20
class can be child of different base class depend on different=20
situation.</P>
<H3>Program 48</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>:
Base1() {
cout << "Base1::Base1" << endl;
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> Base2 {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Base2() {
cout << "Base2::Base2" << endl;
}
};
<SPAN class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>typename</SPAN> T>
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> T {
<SPAN class=3Dcpp-keyword>public</SPAN>:
Drive() {
cout << "Drive::Drive" << endl;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Drive<Base1> obj1;
Drive<Base2> obj2;
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is</P><PRE lang=3Dtext>Base1::Base1
Drive::Drive
Base2::Base2
Drive::Drive
</PRE>
<P>Here the Drive class is inherited from Base1 and Base2 depend =
on the=20
parameter passed to the template at the time of creation of =
object.</P>
<P>ATL use this technique. When you make a COM component using ATL =
then=20
<CODE>CComObject</CODE> is inherit from your class. Here ATL take=20
advantage of template, because ATL doesn't know in advance the =
name of the=20
class which you create to make COM component. CComObject class is =
define=20
in ATLCOM.h file</P>
<P>We can simulate virtual functions too with the help of =
template. Let's=20
recall virtual function once again. Here is a simple program to =
recall the=20
virtual function.</P>
<H3>Program 49</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>:
<SPAN class=3Dcpp-keyword>virtual</SPAN> <SPAN =
class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Base::fun" << endl;
}
<SPAN class=3Dcpp-keyword>void</SPAN> doSomething() {
fun();
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Drive::fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Drive obj;
obj.doSomething();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is </P><PRE lang=3Dtext>Drive::fun
</PRE>
<P>We can get the same behavior with the help of template.</P>
<H3>Program 50</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>typename</SPAN> T>
<SPAN class=3Dcpp-keyword>class</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Base::fun" << endl;
}
<SPAN class=3Dcpp-keyword>void</SPAN> doSomething() {
T* pT =3D <SPAN class=3Dcpp-keyword>static_cast</SPAN><T*>(<SPAN =
class=3Dcpp-keyword>this</SPAN>);
pT->fun();
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base<Drive> {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Drive::fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
Drive obj;
obj.doSomething();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of the program is same as previous one. So we can =
simulate=20
the behavior of virtual function with the help of template.</P>
<P>The interesting parts of this program are</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base<Drive> {
</PRE>
<P>This shows that we can pass the Drive class as a template =
parameter.=20
The other interesting part of the program is the =
<CODE>doSomething</CODE>=20
function of base class.</P><PRE>T* pT =3D <SPAN =
class=3Dcpp-keyword>static_cast</SPAN><T*>(<SPAN =
class=3Dcpp-keyword>this</SPAN>);
pT->fun();</PRE>
<P>Here the base class pointer is converted into drive class =
pointer,=20
because drive class is passed as a template parameter of Base =
class. Then=20
function is executed from that pointer, Now that pointer points to =
drive=20
class object, so the drive class object is called.</P>
<P>But there is very good question, why should we do this? And =
there is=20
very good answer of this question so save the extra byes of =
virtual=20
pointer, virtual table and save the extra time to call virtual =
function.=20
This is the main philosophy of ATL to make component as small as =
possible=20
and as fast as possible.</P>
<P>Now there is one more question may arise in the mind. If due to =
this=20
technique you can simulate virtual function with less memory and =
faster=20
then original virtual function then why should we call virtual =
function?=20
Shouldn't we replace all virtual function with this technique? The =
short=20
answer of this question is no, we can not replace all virtual =
function=20
with this technique. </P>
<P>There are some problems with this technique. First you can not =
further=20
inherit any class from <CODE>Drive</CODE> class. If you try to do =
so then=20
that function will no more act as a virtual function. It doesn't =
happen in=20
the case of virtual function; once you declare function virtual =
then it=20
becomes virtual in all of drive class no matter how deep in =
inheritance=20
chain. Let's take a look at a program what happen when we inherit =
one more=20
class from Drive.</P>
<H3>Program 51</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>typename</SPAN> T>
<SPAN class=3Dcpp-keyword>class</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Base::fun" << endl;
}
<SPAN class=3Dcpp-keyword>void</SPAN> doSomething() {
T* pT =3D <SPAN class=3Dcpp-keyword>static_cast</SPAN><T*>(<SPAN =
class=3Dcpp-keyword>this</SPAN>);
pT->fun();
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> Drive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Base<Drive> {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "Drive::fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>class</SPAN> MostDrive : <SPAN =
class=3Dcpp-keyword>public</SPAN> Drive {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
cout << "MostDrive::fun" << endl;
}
};
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
MostDrive obj;
obj.doSomething();
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this is program as same as previous one. In case =
of=20
virtual function the output should be</P><PRE>MostDrive::fun</PRE>
<P>There is one more problem with this technique, when we want to =
take=20
pointer of <CODE>Base</CODE> class and want to store address of =
drive=20
class.</P>
<H3>Program 52</H3><PRE><SPAN class=3Dcpp-preprocessor>#include =
<iostream></SPAN>
using <SPAN class=3Dcpp-keyword>namespace</SPAN> std;
<SPAN class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>typename</SPAN> T>
<SPAN class=3Dcpp-keyword>class</SPAN> Base {
<SPAN class=3Dcpp-keyword>public</SPAN>:
<SPAN class=3Dcpp-keyword>void</SPAN> fun() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -