RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Imitate Sealed Classes and Disable Object Copying-3 : Page 3

Instantiation and Destruction
While making the constructors private disables subclassing, it raises a new problem: how do you instantiate objects of type noninheritable? Consider:

noninheritable obj(1); //error, can't access private ctor
noninheritable * p = new noninheritable("abc"); //ditto
static noninheritable sobj; //ditto
To solve this problem, add to noninheritable a static member function called create() that returns a pointer to a dynamically allocated noninheritable object. If the class has multiple constructors, you will need to overload create() accordingly:

class noninheritable
  explicit noninheritable(int n);
  explicit noninheritable(const char *);
  static noninheritable * create(int arg) 
   return new noninheritable(arg);
  static noninheritable * create(const char* arg) 
   return new noninheritable(arg);
To instantiate an object, call the matching overloaded version of create():

noninheritable * pstr = noninheritable::create("abc");
noninheritable * pi = noninheritable::create(5);
This works because create() has unrestricted access to all members of its class, including private ones. To destroy the object, simply use delete as usual:

delete pstr;
delete pi;
create() can allocate only one object at a time. To enable the instantiation of arrays (if necessary), define additional static member functions. Don't be tempted to add an extra argument to the existing versions of create() as this could lead to confusion. Instead, give the array version a descriptive name such as create_array(). Remember, also, that the said class must have a default constructor to allow the creation of arrays.

Disabling Object Copying
C++ automatically declares a public copy constructor and a public assignment operator for a class that doesn't declare these members explicitly. Yet in some cases, copying an object of a certain class is undesirable. File stream objects are a good example of this. If fstream objects were copyable, a program might accidentally have two objects accessing the same file simultaneously. Fortunately, the designers of the <fstream> library prevented this from happening by disabling object copying. You can adopt the same technique in other classes as well. To disable copying, declare the copy constructor and the assignment operator as private. You don't need to define these private member functions though. The explicit private declarations ensure that the compiler doesn't declare them implicitly as public. Here's an example:

class nocopy
private: //block object copying
 nocopy(const nocopy &);
 nocopy& operator=(const nocopy &);

public: //enable instantiation
 nocopy() {}
 ~nocopy() {}

nocopy nc, nc2; //OK, using public default ctor & dtor
nocopy nc3(nc);//error, copy ctor is inaccssible
nc2=nc;//error, operator= is inaccessible
If you have several classes that need to enforce the non-copyable constraint, you may use Boost's noncopyable class as a private base class for every class whose objects must not be copied. boost::noncopyable doesn't have any data members. As such, it shouldn't increase the size of classes derived from it. This is known as the empty base class optimization.

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date