C++利用构造函数限制对象的创建

在上一节构造函数的例 1 中,我们提到,如果不声明默认构造函数 book(),而只声明带参构造函数 book(char *a, double p) 的时候,语句book Alice;是无法创建对象的。无法创建的原因在上一节已经讲明,这节就不再赘述了。

不过类的构造函数的这一特性却可以用来限制对象的创建。

【例 1】还是用 book 类来说明这节的内容:
class book
{
public:
    void setprice(double a);
    double getprice();
    void settitle(char* a);
    char * gettitle();
    void display();
private:
    double price;
    char * title;
};
首先需要知道的是,在什么样的情况下才需要限制对象的创建?限制对象的创建不代表我们想禁止创建对象,只是加以限制而已,限制创建对象时能够按照我们需要的那样创建,而不能随意的创建对象。

比如例 1 中,我们定义了一个 book 类,声明对象的时候自然是为了描述某一本具体的书,这个时候如果我们直接采用book a;这样的方式创建一个对象 a,编译当然是不会有问题的,毕竟系统会自动生成默认构造函数的。但是这样创建的对象 a 能代表什么呢?指的又是哪一本书?完全不清楚!

如果这个时候我们直接调用 a.display() 函数,那会发生什么就不好说了,毕竟 a.price 和 a.title 都没有初始化。这就是一个比较危险的程序了。不过肯定有人会说,不是可以通过 a.setprice() 和 a.settitle() 函数对两个成员变量进行赋值么?不错,确实可以这么做,但是万一给忘掉了呢?

对于这样的一个类,类的设计人员如果让book a;这样的创建对象的方式不成立,并且每次创建对象的时候就必须给书本的 price 和 title 赋值,这样问题不就解决了么?

这样的想法能实现么?回答是肯定的。我们可以通过构造函数来实现这一功能。看下面的几个类的示例。

【例 2】不声明默认构造函数:
class book
{
public:
    book(char *a, double p);
    void setprice(double a);
    double getprice();
    void settitle(char* a);
    char * gettitle();
    void display();
private:
    double price;
    char * title;
};

【例 3】将默认构造函数声明为 private:
class book
{
public:
    book(char *a, double p);
    void setprice(double a);
    double getprice();
    void settitle(char* a);
    char * gettitle();
    void display();
private:
book(){}
    double price;
    char * title;
};
在例 2 中,我们在类中声明了一个带参构造函数book(char *a, double p);,如此一来默认构造函数就不会被系统自动生成了,也即不会生成 book(){} 这个构造函数,如此一来创建对象book a;则会出现编译错误。要想正确创建对象则必须进行初始化,如book Alice("Alice in Wonderland", 29.9);

除了此种手段之外,例 3 的做法也是可行的,我们将默认构造函数主动声明并定义,最关键的是将其设置为 private 属性,也就是说无法在类外进行访问,如此一来book a;同样会报出编译错误,只不过这一次的错误是因为访问权限的问题,此时如果想要声明对象,则还是必须通过 public 属性的带参构造函数book(char *a, double p);来声明对象。

根据上面的几个例子,我们将系统不会自动生成默认构造函数的情况总结如下:
  • 类中显式地声明了默认构造函数,无论其属性被设置为 public、private 还是 protected,系统都不会再自动生成默认构造函数了;
  • 类中显式地声明了其它任意一个不是默认构造函数的构造函数,系统均不会再自动生成默认构造函数。

其实这两点可以总结为一点,那就是当类中显示地声明了任意一个构造函数,系统均不会再自动生成构造函数。在例 2 中我们是采用第二种情况避免默认构造函数的产生,从而限制了类对象的随意创建。

在 C++ 中,之所以利用构造函数限制类对象的创建,意图已经很明显了,那就是要求程序设计人员在使用类创建对象的时候能够正确地进行初始化。

声明为 private 属性的构造函数,与声明为 private 属性的成员变量或普通成员函数一样,在类外同样是不能访问的,我们可以巧妙地使用这一点,限制类对象的随意创建。