#include <iostream>Firstly, class name CDerive1 and CDerive2 were declared and in the same line already were used for the inheritance list:
using namespace std;
template <class T>
class CBaseT
{
public:
void SayHi()
{
T* pT = static_cast<T*>(this);
pT->ClassName();
}
void ClassName()
{
cout << "This is class CBaseT" << endl;
}
};
class CDerive1 : public CBaseT<CDerive1>
{
};
class CDerive2 : public CBaseT<CDerive2>
{
public:
void ClassName()
{
cout << "This is class CDerived2" << endl;
}
};
int main()
{
CDerive1 one;
CDerive2 two;
one.SayHi();
two.SayHi();
}
class CDerive1 : public CBaseT<CDerive1>
It is legal, because C++ standard allows to use the name immediately after the definition. This trick allowed the second thing for this code - compile-time virtual function:
void ClassName()
This function is not declared as the virtual function, but, in fact, the application screenshot shows that it behaves exactly as the virtual method.
The trick here is
If we use the templates in the usual way, we have to check the pointer, and if it is not NULL, we can call the method as it is shown here:
T* pT = static_cast<T*>(this);in SayHi method of the CBaseT class. It casts type CBaseT to either CDerive1 or CDerive2 depending on which specialization is being invoked. Because template code is generated at compile-time, this cast is safe, because the this object can be only CDerive1 or CDerive2 and nothing else.
#include <iostream>Check for NULL in the ATL-style templates simply does not exist - it is the this pointer.
using namespace std;
template <class T>
class CTestT
{
public:
void SayHi(T* pT)
{
if (pT != NULL)
pT->ClassName();
}
};
class CTest
{
public:
void ClassName()
{
cout << "This is CTest" << endl;
}
};
int main()
{
CTest test;
CTestT<CTest> one_more_test;
one_more_test.SayHi(&test);
return 0;
}
The trouble will happen, if I will write:
class CDerive2 : public CBaseT<CDerive1>So the benefits are obvious:
- It does not require using pointers to objects.
- It saves memory because there is no need for the virtual functions' table.
- It's impossible to call a virtual function through a NULL pointer at run-time because of unintialized vtbl.
- All function calls are resolved at compile-time, so they can be optimized.
- A template should be used to generate a collection of classes when the type of the objects does not affect the behavior of the class's functions.
- Inheritance should be used for a collection of classes when the type of the objects does affect the behavior of the class's functions.
No comments:
Post a Comment