Re: Virtual constructor?
Ulrich Eckhardt wrote:
Seungbeom Kim wrote:
Otherwise, if it's used to mean an idiom, you *can* implement a virtual
default constructor just as a virtual copy constructor: something that
depends on an existing object and creates a new one of the same type.
Right.
I admit that my statements were not very precise. Indeed, in the same way
that you can implement a 'virtual' copy constructor, where the created
object's type depends on another object's type, you can create a 'virtual'
default constructor.
One big difference between a constructor and a copy constructor is that in
one case an object is created and in the other, an object is created and
made a copy of an existing object. The second case thus lends itself much
better to making it polymorphic than the first, because you always have a
second object involved. Also, the requirement for a 'virtual copy
constructor' is much more common than the requirement for a 'virtual
constructor'.
I fully agree that technically both are possible, though.
If it had been just for a purely technical possibility,
I wouldn't have bothered to post the previous article. ;-)
Let me share with you an experience of mine: I have actually implemented
and used 'virtual' constructors that did not clone existing objects but
created new ones. (Strictly they weren't 'default' constructors, though,
but they didn't copy anything from existing objects (of the same type).)
I had a class hierarchy of messages, which are serialized from/into a
byte stream. Each message class had a distinct type ID and a virtual
constructor that took a byte stream as its argument.
struct message
{
virtual ~message() { }
virtual uint16_t message_type() const = 0;
virtual message* create(istream&) const = 0;
};
struct some_message : message
{
virtual uint16_t message_type() const { return 0xCAFEu; }
virtual message* create(istream& s) const
{ return new some_message(s); }
explicit some_message(istream& s) /* : ... */ { /* ... */ }
// ...
};
// lots of other messages
And a map from type IDs into default constructed messages were built.
std::map<uint16_t, const message*> msg_map;
void register(const message* m) { msg_map[m->message_type()] = m; }
register(new some_message);
// ...
Later when a message is to be reconstructed from a byte stream, its type
ID was read first, and the map was looked up for the type ID, and the
virtual default constructor (called "create") was called:
istream& is;
uint16_t msg_type;
is >> msg_type;
const msg_info& i = msg_map.find(msg_type)->second;
// error checking not shown here for brevity
std::auto_ptr<message> msg(i.prototype->create(is));
The information flow is like the following:
("prototype") (real message)
uint16_t -----------> message* --------------> message*
map::find virtual ctor
I hope this example will be helpful.
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]