I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
开发者_开发技巧 template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely, Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor
. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print
精彩评论