Wednesday, July 6, 2011

virtual constructor in c++

/*
 * virtual constructor in c++
 */

An idiom that allows you to do something that C++ doesn't directly support.
You can get the effect of a virtual constructor by a virtual clone() member function (for copy constructing), or a virtual create() member function (for the default constructor). 

class CShape {
     public:
           virtual ~Shape() { } // A virtual destructor
           virtual void draw() = 0; // A pure virtual function
           virtual void move() = 0;
           /*
            *   do your some stuffs
            */
           virtual Shape* clone() const = 0; // Uses the copy constructor
           virtual Shape* create() const = 0; // Uses the default constructor
};

class Circle : public Shape {
     public:
     Circle* clone() const; // Covariant Return Types; see below
     Circle* create() const; // Covariant Return Types; see below
     /*
      *   do your some stuffs
      */
};

Circle* Circle::clone() const {
     return new Circle(*this);
}
Circle* Circle::create() const {
     return new Circle();

In the clone() member function, the new Circle(*this) code calls Circle's copy constructor to copy the state of this into the newly created Circle object. (Note: unless Circle is known to be final (AKA a leaf), you can reduce the chance of slicing by making its copy constructor protected.) In the create() member function, the new Circle() code calls Circle's default constructor.

Users use these as if they were "virtual constructors" :
void userCode(Shape& s) {
Shape* s2 = s.clone();
Shape* s3 = s.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}

This function will work correctly regardless of whether the Shape is a Circle, Square, or some other kind-of Shape that doesn't even exist yet. 
Note: The return type of Circle's clone() member function is intentionally different from the return type of Shape's clone() member function. This is called Covariant Return Types, a feature that was not originally part of the language. If your compiler complains at the declaration of Circle* clone() const within class Circle (e.g., saying "The return type is different" or "The member function's type differs from the base class virtual function by return type alone"), you have an old compiler and you'll have to change the return type to Shape*.

Note: If you are using Microsoft Visual C++ 6.0, you need to change the return types in the derived classes to Shape*. This is because MS VC++ 6.0 does not support this feature of the language. Please do not write me about this; the above code is correct with respect to the C++ Standard (see 10.3p5); the problem is with MS VC++ 6.0. Fortunately covariant return types are properly supported by MS VC++ 7.0.

No comments:

Post a Comment