Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!elroy.jpl.nasa.gov!decwrl!world!wmm From: wmm@world.std.com (William M Miller) Newsgroups: comp.lang.c++ Subject: Re: Virtrual memory allocation Message-ID: <1991Mar21.023024.14896@world.std.com> Date: 21 Mar 91 02:30:24 GMT References: <1896@news.tcs.com> <13476@helios.TAMU.EDU> <1991Mar20.224829.2611@lia> Organization: The World Public Access UNIX, Brookline, MA Lines: 109 jgro@lia (Jeremy Grodberg) writes: > The method which I like best, and which seems to raise the fewest objections, > is to create a virtual method called clone() in your base class (Position), > which returns a copy of the object. Yes, you must override it everywhere, > but if you forget, you just get the base class part, instead of a core dump > (although to some people this is not an advantage). Unfortunately, as with > asking an object for its type, there is no way in C++ to have the compiler > do all the work for you; you will have to rely on programming everything > correctly. Clone(), however, is trivial enough that if you remember to > do it at all, you will do it right. Here's a technique I use for making sure that I don't forget to do things in a derived class. It relies on the fact that a virtual base class with no default constructor MUST be initialized in the most derived class; the compiler will not allow you to forget to initialize it. In the example below, the intializer is intended to be a string containing the name of the class; the clone() member function can use that value to ensure that it is not being invoked for an object of an unexpected class, as would be the case if the author of a derived class neglects to provide a clone() override. Here's a brief demonstration of the technique: #include #include #include class my_name_is { public: my_name_is(const char* nm): my_name(nm) { } int this_is(const char* the_name) { return strcmp(my_name, the_name) == 0; } void error() { fprintf(stderr, "Need %s::clone()!\a\n", my_name); exit(999); } private: const char* my_name; }; class Base: public virtual my_name_is { public: Base(): my_name_is("Base") { } virtual Base* clone() { if (!this_is("Base")) error(); return new Base(); } virtual void say_my_name() { printf("Base\n"); } }; class Derived1: public Base { public: Derived1(): my_name_is("Derived1") { } Base* clone() { if (!this_is("Derived1")) error(); return new Derived1(); } void say_my_name() { printf("Derived1\n"); } }; class Derived2: public Base { public: Derived2(): my_name_is("Derived2") { } // Oops, forgot clone()! void say_my_name() { printf("Derived2\n"); } }; int main() { Base* bp = new Base; bp = bp->clone(); bp->say_my_name(); bp = new Derived1; bp = bp->clone(); bp->say_my_name(); bp = new Derived2; bp = bp->clone(); bp->say_my_name(); return 0; } If you omit an initialization of "my_name_is" in a class derived from Base, the compiler will report an error. The result of running this program is Base Derived1 Need Derived2::clone()! -- William M. Miller, Glockenspiel, Ltd. wmm@world.std.com