Mimic virtual functions with templates

M

Martin

Greetings

I want to have virtual member functionality, but without my member
functions
being virtual:)

As of yet this is all just in my head cause I can't see a nice
solution yet so lets start with some simple code.


template <class T>
class Base
{
public:
void Func()
{
T* ptrT = static_cast<*T>(this);
pT->FuncImpl();
};
protected:
void FuncImpl() {std::cout << "This is Base"<<std::endl;}
};

class DerivedOne : public Base<DerivedOne>
{
public:
void FuncImpl() {std::cout <<"This is DerivedOne"<<std::endl; }
};

class DerivedTwo : public Base<DerivedTwo>
{
public:
void FuncImpl() {std::cout <<"This is DerivedTwo"<<std::endl; }
};

The thing I want to be able to todo is something like this

Base * b = GetSomeDerivedClass();
b->Func();

I'm quite sure this won't work as Base is a template class, but how
can I achieve something similar?
I recently read about someone wanting to store template classes of
different
types in an STL container, which is sort of similar to my problem and
one
of the suggestions was to use boost::any.
Is that the only suggestion if it is a solution at all?


Martin
 
R

Rolf Magnus

Martin said:
Greetings

I want to have virtual member functionality, but without my member
functions being virtual:)

For which reason?
As of yet this is all just in my head cause I can't see a nice
solution yet so lets start with some simple code.


template <class T>
class Base
{
public:
void Func()
{
T* ptrT = static_cast<*T>(this);
pT->FuncImpl();
};
protected:
void FuncImpl() {std::cout << "This is Base"<<std::endl;}
};

class DerivedOne : public Base<DerivedOne>
{
public:
void FuncImpl() {std::cout <<"This is DerivedOne"<<std::endl; }
};

class DerivedTwo : public Base<DerivedTwo>
{
public:
void FuncImpl() {std::cout <<"This is DerivedTwo"<<std::endl; }
};

The thing I want to be able to todo is something like this

Base * b = GetSomeDerivedClass();
b->Func();

I'm quite sure this won't work as Base is a template class, but how
can I achieve something similar?

So you want to do dynamic dispatching, i.e. call a function, but decide at
runtime which one is actually to be called. In this case, you need some way
to dynamically find out the actual type of your object and then select the
function belonging to that type. The normal C++ way with virtual functions
is usually implemented as an extra hidden member variable that is a pointer
to a table of function pointers (called the vtable). Based on the type, the
according vtable is selected and based on the function you specified, the
table is indexed to find the pointer to that function. At least that's the
way that every compiler I know about uses.
Your template way doesn't work, because templates can only do static
dispatching, i.e. the actual function to be called is selected at compile
time.
I recently read about someone wanting to store template classes of
different types in an STL container, which is sort of similar to my
problem and one of the suggestions was to use boost::any.
Is that the only suggestion if it is a solution at all?

Well, boost::any uses a combination of templates and virtual member
functions, AFAIK. Why exactly would you need your solution to not use
virtual member functions?
 
J

Jesper Madsen

You can get to about here:

class Dog {
public:
void sound() const { std::cout << "vuf!" << std::endl; };
};

class Cat {
public:
void sound() const { std::cout << "Miauw!" << std::endl; };
};

class Parrot {
public:
void sound() const { std::cout << "Squark!" << std::endl; };
};

template <class T> void makeNoise(const T& obj) {
obj.sound();
};



int main(int /*argc*/,char*[] /*argv*/)
{

makeNoise(Dog());
makeNoise(Cat());
makeNoise(Parrot());
return 0;
}

Or if you want your member functions truly dynamic, take a pointer to member
and store in a protected variable in the base class...

Sry. but I am not sure what the purpose for it is!!!?
 
M

Martin

Well I guess I should explain myself.

I have a "packet decoder" that uses the Strategy pattern.
There's a hash_map which maps packet types to PacketDecoders(which all
inherits from AbstractDecoder).

struct AbstractDecoder
{
virtual UInt16 Decode(Byte *pBuf, UInt16 iBufSize) = 0;
};
struct SpecialDecoderOne : public AbstractDecoder
{
virtual UInt16 Decode(Byte *pBuf, UInt16 iBufSize)
{
std::cout << "Decoding message type 1"<<std::endl;
return 1;
}
};

typedef stdext::hash_map<const
UInt16,AbstractDecoder*,std::equal_to<UInt16> > DecoderStrategy;
typedef DecoderStrategy::const_iterator Iter;

DecoderStrategy decoders;

//here we relay the decoding to the special packet decoder.
UInt16 PacketHandler::Decode(UInt16 type, Byte *pBuf, UInt16 iBufSize)
{
Iter iter, end = decoders.end();
if((iter = decoders.find(type)) != end)
{
return *iter->Decode(pBuf, iBufSize);
}
throw PacketDecoderNotFoundException(type);
}

I'd ultimately like to lose the virtual functions by using the inherit
from template parameter trick

template <class T>
class AbstractDecoder
{
public:
UInt16 Decode(Byte *pBuf, UInt16 iBufSize)
{
T *pT = static_cast<T*>(this);
return pT->DecodeImpl(pBuf, iBufSize);
}
protected:
UInt16 DecodeImpl(Byte *pBuf, UInt16 iBufSize)
{
std::cout <<"OOPS no DecodeImpl in subclass"<<std::endl;
}
};

struct SpecialDecoderOne : public AbstractDecoder<SpecialDecoderOne>
{
UInt16 DecodeImpl(Byte *pBuf, UInt16 iBufSize)
{
std::cout << "Decoding message type 1"<<std::endl;
return 1;
}
};

The reason to this is I want the decoder to be as efficient as
possible short
of doing a big switch(type) over all the different packets.

I will accept if it's not possible to achieve this in anyway though
:)

edit: please overlook any missing "const" :p
 
J

Jesper Madsen

//here we relay the decoding to the special packet decoder.
UInt16 PacketHandler::Decode(UInt16 type, Byte *pBuf, UInt16 iBufSize)
{
Iter iter, end = decoders.end();
if((iter = decoders.find(type)) != end)
{
return *iter->Decode(pBuf, iBufSize);
}
throw PacketDecoderNotFoundException(type);
}

The question is if UInt16 type can be known at compile time.. I guess it
cannot... but I tried to see how close I could get... And the solution
involves a function pointer array, instead of a case, but I do get rid of
the virtual function....

I have no idea how this will perform, so you will have to give it a go...
with a profiler...

Hope this will help you in any way ...

Jesper



enum encoder {
kSpecialDecoderOne=0,
kSpecialDecoderTwo
};


typedef short (*DecodePtr) (void*,short);

struct UnknownPackage {
};

template <encoder T>
struct Decoder
{
encoder T;
short Decode(void *pBuf, short iBufSize);
};

template <>
struct Decoder<kSpecialDecoderOne>
{
encoder kSpecialDecoderOne;
static short Decode(void *pBuf, short iBufSize)
{
std::cout << "Decoding message type 1"<<std::endl;
return 1;
}
};

template <>
struct Decoder<kSpecialDecoderTwo>
{
encoder kSpecialDecoderTwo;
static short Decode(void *pBuf, short iBufSize)
{
std::cout << "Decoding message type 2"<<std::endl;
return 1;
}
};

struct PacketHandler {
short Decode(encoder typeI, void *pBuf, short iBufSize)
{
static DecodePtr typeArray[]={ (&Decoder<kSpecialDecoderOne>::Decode) ,
&Decoder<kSpecialDecoderTwo>::Decode };
static unsigned long arraySize = sizeof(typeArray)/sizeof(DecodePtr);

//array boundscheck
if (typeI>=0 && typeI<arraySize)
return typeArray[typeI](pBuf,iBufSize);
throw UnknownPackage();
}
};

int main(int /*argc*/,char*[] /*argv*/)
{
PacketHandler packetHandler;
packetHandler.Decode(kSpecialDecoderOne,0,0);
packetHandler.Decode(kSpecialDecoderTwo,0,0);


return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top