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
{
private:
explicit noninheritable(int n);
explicit noninheritable(const char *);
public:
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.