M
Mike Smith
Sorry about the multiple post, but I just realized my prior post was in
a thread that dates back a couple of days, so people might not see it.
Which is considered better for writing interfaces in C++: abstract base
classes, or templates - and why? I.e. when is one preferable over the
other?
Let's suppose, just by way of an example, that I want to specify an
interface for classes that can "pickle" themselves; i.e. read/write
their state information to a "flat" binary storage (for serialization,
or message-passing, etc.) It occurs to me that there are two ways one
could do this, one using an abstract base class:
typedef std::vector<unsigned char> ByteVector;
struct IPickle
{
virtual void Pickle(ByteVector &bv) = 0; // write state to vector
virtual void Unpickle(ByteVector &bv) = 0; // get state from vector
};
then one could create classes that inherit from IPickle and implement
the functions:
class PickleSample : public IPickle
{
void Pickle(...) {...}
void Unpickle(...) {...}
};
Or, one could use the Curiously Recurring Template Pattern (that is, if
I'm using it correctly):
template <class T> struct TPickle
{
void Pickle(ByteVector &bv) {T:ickle(bv);}
void Unpickle(ByteVector &bv) {T::Unpickle(bv);}
};
class PickleSample : public TPickle<PickleSample>
{
...
};
What are the pros and cons of each? The ABC approach lets you do things
like this:
void PickleAndSendMessage(IPickle *p_obj)
{
ByteVector bv;
p_obj->Pickle(bv);
SendMessageUsingSomeTransport(&bv[0], bv.size());
}
i.e. where PickleAndSendMessage() can work with any object that
"exposes" the IPickle interface. If I understand correctly, this would
not be possible with the CRTP approach. I thought maybe that an
advantage of the CRTP would be that it would be easier to "bolt on"
Pickle functionality to an existing class, e.g.:
// pre-existing class
class Blorf
{
int foo, bar;
public:
// some functions here
};
// new class with pickling
class PickleBlorf : public Blorf, public TPickle<PickleBlorf>
{
public:
PickleBlorf() : Blorf() {}
void Pickle(ByteVector &bv) {/*write foo and bar into bv*/}
void Unpickle(ByteVector &bv) {/*get foo and bar from bv*/}
};
but then I realized that this could just as easily be done using the ABC
approach - instead of inheriting from TPickle<PickleBlorf> above, you
would just inherit from IPickle instead.
So what's the downside of the ABC approach? What am I missing about the
Curiously Recurring Template Pattern that's got everybody talking about
it? Why not just use ABCs instead? Is it the fact that they lead to
the creation of a vtable? Is that such a big deal?
Thanks,
a thread that dates back a couple of days, so people might not see it.
Which is considered better for writing interfaces in C++: abstract base
classes, or templates - and why? I.e. when is one preferable over the
other?
Let's suppose, just by way of an example, that I want to specify an
interface for classes that can "pickle" themselves; i.e. read/write
their state information to a "flat" binary storage (for serialization,
or message-passing, etc.) It occurs to me that there are two ways one
could do this, one using an abstract base class:
typedef std::vector<unsigned char> ByteVector;
struct IPickle
{
virtual void Pickle(ByteVector &bv) = 0; // write state to vector
virtual void Unpickle(ByteVector &bv) = 0; // get state from vector
};
then one could create classes that inherit from IPickle and implement
the functions:
class PickleSample : public IPickle
{
void Pickle(...) {...}
void Unpickle(...) {...}
};
Or, one could use the Curiously Recurring Template Pattern (that is, if
I'm using it correctly):
template <class T> struct TPickle
{
void Pickle(ByteVector &bv) {T:ickle(bv);}
void Unpickle(ByteVector &bv) {T::Unpickle(bv);}
};
class PickleSample : public TPickle<PickleSample>
{
...
};
What are the pros and cons of each? The ABC approach lets you do things
like this:
void PickleAndSendMessage(IPickle *p_obj)
{
ByteVector bv;
p_obj->Pickle(bv);
SendMessageUsingSomeTransport(&bv[0], bv.size());
}
i.e. where PickleAndSendMessage() can work with any object that
"exposes" the IPickle interface. If I understand correctly, this would
not be possible with the CRTP approach. I thought maybe that an
advantage of the CRTP would be that it would be easier to "bolt on"
Pickle functionality to an existing class, e.g.:
// pre-existing class
class Blorf
{
int foo, bar;
public:
// some functions here
};
// new class with pickling
class PickleBlorf : public Blorf, public TPickle<PickleBlorf>
{
public:
PickleBlorf() : Blorf() {}
void Pickle(ByteVector &bv) {/*write foo and bar into bv*/}
void Unpickle(ByteVector &bv) {/*get foo and bar from bv*/}
};
but then I realized that this could just as easily be done using the ABC
approach - instead of inheriting from TPickle<PickleBlorf> above, you
would just inherit from IPickle instead.
So what's the downside of the ABC approach? What am I missing about the
Curiously Recurring Template Pattern that's got everybody talking about
it? Why not just use ABCs instead? Is it the fact that they lead to
the creation of a vtable? Is that such a big deal?
Thanks,