3

I have implemented serialisation by making sure that classes in an inheritance hierarchy implement virtual read and write functions:

class base
{
     ...

     virtual void read(std::istream&)=0;
     virtual void write(std::ostream&) const=0;
     virtual std::string is_a() const;
};

BEGIN_NAMESPACE_1(io)
    SERIALISE(base)
END_NAMESPACE_1

where the macro "SERIALISE" implements an overload of a "serialise" and a "deserialise" function to allow easy i/o via the base class pointer:

#define SERIALISE(TYPE)\
void deserialise( boost::shared_ptr<TYPE>& dat, std::istream& ifs )\
{\
    std::string type;\
    read(type, ifs);\
\
    dat = TYPE::make_##TYPE(type);\
    dat->read(ifs);\
}\
\
void serialise( const boost::shared_ptr<TYPE>& dat, std::ofstream& ofs )\
{\
    write(dat->is_a(), ofs);\
    dat->write(ofs);\
}

However, if the base class contains pure virtual functions, I get a compiler error "cannot allocate object of abstract type "base" because the following functions are pure within "base"...", presumably because the compiler attempts to instantiate the abstract base class when the class name is passed to the macro invocation. Is there a way of salvaging this i/o design?

user588241
  • 239
  • 3
  • 10
  • We can't answer this if you don't show us what the macro contains or what the compiler error is... – interjay Oct 22 '12 at 12:50
  • Ok, sorry, I've updated the question, hopefully it now includes enough detail. I thought I was making a simple mistake when dealing with a standard problem... – user588241 Oct 22 '12 at 13:14
  • Provide a function definition for the pure virtual functions that are prototyped. Although a member function may be pure virtual, it's allowable to provide a function definition, not just a prototype within the base class. This definition is callable from derived classes. – damienh Oct 22 '12 at 13:17
  • You can replace the macro call with its actual expansion for one of your abstract classes and check the compiler error. It will be much easier to track down that way. – Gorpik Oct 22 '12 at 13:21
  • in reply to damienh: That doesn't seem to fix it, although of course it works if I make the methods virtual. I don't really want the base to be instantiated though. – user588241 Oct 22 '12 at 13:24
  • You could use a class factory with mapped function pointers. see: http://stackoverflow.com/questions/1096700/instantiate-class-from-name –  Oct 22 '12 at 13:30

1 Answers1

1

You cannot instantiate an abstract base class or use it as a value parameter to a function.

template explicit shared_ptr(Y * p); Requirements: p must be convertible to T *. Y must be a complete type. The expression delete p must be well-formed, must not invoke undefined behavior, and must not throw exceptions.

Effects: Constructs a shared_ptr that owns the pointer p.

Postconditions: use_count() == 1 && get() == p.

Throws: std::bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.

Exception safety: If an exception is thrown, delete p is called.

Notes: p must be a pointer to an object that was allocated via a C++ new expression or be 0. The postcondition that use count is 1 holds even if p is 0; invoking delete on a pointer that has a value of 0 is harmless.

In this case the compiler does not have to resolve template shared_ptr as a having values of type TYPE inside because these can never be instantiated.

Konstantin Dinev
  • 34,219
  • 14
  • 75
  • 100
  • My problem is that the serialise/deserialise functions should be in terms of shared_ptr. Are you suggesting the shared_ptrs should hold pointer types? – user588241 Oct 22 '12 at 15:41
  • afaik the template parameter in shared_ptr refers to the type of a pointer, at no point is the type instantiated as a value, storing a pointer in a shared_ptr just doesn't seem to make sense... – user588241 Oct 23 '12 at 10:26
  • @user588241 Sorry I was wrong, you cannot do that. I have left a quote from the documentation. – Konstantin Dinev Oct 23 '12 at 10:40