在类中创建私有构造函数有什么用?

时间:2010-01-14 06:29:09

标签: oop

为什么我们要在类中将构造函数设为私有?因为我们总是需要将构造函数公开。

24 个答案:

答案 0 :(得分:120)

您可能需要私有构造函数的一些原因:

  1. 只能从类本身内的静态工厂方法访问构造函数。 Singleton也可以属于这一类。
  2. 实用程序类,仅包含静态方法。

答案 1 :(得分:91)

通过提供私有构造函数,可以防止在除此类之外的任何位置创建类实例。提供此类构造函数有几种用例。

一个。您的类实例是使用static方法创建的。然后将static方法声明为public

class MyClass()
{
private:
  MyClass() { }

public:
  static MyClass * CreateInstance() { return new MyClass(); }
};

B中。您的班级是单身人士。这意味着,程序中只存在一个类的实例。

class MyClass()
{
private:
  MyClass() { }

public:
  MyClass & Instance()
  {
    static MyClass * aGlobalInst = new MyClass();
    return *aGlobalInst;
  }
};

℃。 (仅适用于即将推出的C ++ 0x标准)您有几个构造函数。其中一些是public,另一些是private。为了减少代码大小,公共构造函数“调用”私有构造函数,这些构造函数反过来完成所有工作。因此,您的public构造函数称为委派构造函数:

class MyClass
{
public:
  MyClass() : MyClass(2010, 1, 1) { }

private:
  MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};

d。您希望限制对象复制(例如,由于使用共享资源):

class MyClass
{
  SharedResource * myResource;

private:
  MyClass(const MyClass & theOriginal) { }
};

电子。您的类是实用程序类。这意味着,它只包含static个成员。在这种情况下,不能在程序中创建任何对象实例。

答案 2 :(得分:12)

留下“后门”,允许其他朋友类/功能以禁止用户的方式构建对象。想到的一个例子是构造迭代器(C ++)的容器:

Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
//     and Container is a friend of Iterator.

答案 3 :(得分:9)

每个人都被困在单身人士身上,哇。

其他事项:

  • 阻止人们在堆栈上创建你的课程;使用私有构造函数,只通过工厂方法返回指针。
  • 防止创建类的副本(私有拷贝构造函数)

答案 4 :(得分:7)

这对包含公共代码的构造函数非常有用;私有构造函数可以被其他构造函数调用,使用'this(...);'符号。通过在私有(或受保护的)构造函数中创建公共初始化代码,您还明确表明它仅在构造期间被调用,如果它只是一个方法,则不是这样:

public class Point {
   public Point() {
     this(0,0); // call common constructor
   }
   private Point(int x,int y) {
     m_x = x; m_y = y;
   }
};

答案 5 :(得分:3)

在某些情况下,您可能不想使用公共构造函数;例如,如果你想要一个单例类。

如果您正在编写第三方使用的程序集,则可能有许多内部类,您只需要由程序集创建,而不是由程序集的用户实例化。

答案 6 :(得分:3)

这可以确保您(具有私有构造函数的类)控制如何调用构造函数。

示例:类上的静态工厂方法可以返回对象,因为工厂方法选择分配它们(例如,像单件工厂)。

答案 7 :(得分:3)

我们也可以拥有私有构造函数, 通过特定的类来创建对象的创建 仅(出于安全原因)。

这样做的一种方法是通过朋友班。

C ++示例:

class ClientClass;
class SecureClass 
{
  private:
    SecureClass();   // Constructor is private.
    friend class ClientClass;  // All methods in 
                               //ClientClass have access to private
                               // &   protected methods of SecureClass.
};

class ClientClass
{
public:
    ClientClass();
    SecureClass* CreateSecureClass()
     { 
           return (new SecureClass());  // we can access 
                                        // constructor of 
                                        // SecureClass as 
                                        // ClientClass is friend 
                                        // of SecureClass.
     }
};

注意:注意:只有ClientClass(因为它是SecureClass的朋友)  可以调用SecureClass的构造函数。

答案 8 :(得分:2)

答案 9 :(得分:1)

我看到你提出的一个问题,解决了同样的问题。

如果您不想让其他人创建实例,那么只需将构造器保持在有限的范围内。实际应用(一个例子)是单例模式。

答案 10 :(得分:1)

不应该使构造函数成为私有的。期。使其受到保护,因此您可以根据需要扩展该类。

编辑:无论你投入多少次投票,我都会站在那里。 你正在切断代码未来发展的潜力。如果其他用户或程序员确实要扩展该类,那么他们只需将构造函数更改为源或字节码中的受保护。除了让自己的生活更加艰难之外,你将一无所获。在构造函数的注释中包含警告,并将其保留在该注释中。

如果它是一个实用程序类,更简单,更正确,更优雅的解决方案是将整个类标记为“静态final”以防止扩展。将构造函数标记为私有没有任何好处;一个真正确定的用户可能总是使用反射来获取构造函数。

有效用途:

  • protected的好用 构造函数是强制使用静态的 工厂方法,允许你 限制实例化或池&重用 昂贵的资源(数据库连接, 本地资源)。
  • 单身人士(通常不是很好的练习,但有时是必要的)

答案 11 :(得分:1)

如果您不希望用户创建此类的实例或创建继承此类的类(如java.lang.math),则此包中的所有函数均为static,则可以调用所有函数无需创建math的实例,因此构造函数将声明为静态。

答案 12 :(得分:1)

如果它是私人的,那么你就不能称之为==>你无法实例化这个类。在某些情况下很有用,比如单身人士。

有一个讨论和更多例子here

答案 13 :(得分:1)

您可以拥有多个构造函数。如果您没有显式提供,则C ++提供默认构造函数和默认复制构造函数。假设您有一个只能使用某些参数化构造函数构造的类。也许它初始化变量。如果用户在没有该构造函数的情况下使用此类,则它们可能导致无问题。一个很好的一般规则:如果默认实现无效,请将默认实现和复制构造函数设为私有,并且不提供实现:

class C
{
public:
    C(int x);

private:
    C();
    C(const C &);
};

使用编译器阻止用户将该对象与默认的无效构造函数一起使用。

答案 14 :(得分:1)

构造函数是私有的,例如当您需要实现单例或限制类的对象数时。 例如,在单例实现中,我们必须使构造函数成为私有

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i==0)
        {

            instance =new singletonClass;
            i=1;

        }

        return instance;

    }
    void test()
    {

        cout<<"successfully created instance";
    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//////return instance!!!
    temp->test();
}

再次,如果您想将对象创建限制为10,请使用以下

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i<10)
        {

            instance =new singletonClass;
            i++;
            cout<<"created";

        }

        return instance;

    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//return an instance
    singletonClass *temp1=singletonClass::createInstance();///return another instance

}

谢谢

答案 15 :(得分:0)

如果创建私有构造函数,则需要在类内部创建对象

enter code here#include<iostream>
//factory method
using namespace std;
class Test
{
private:
Test(){
cout<<"Object created"<<endl;
}
public:
static Test* m1(){
    Test *t = new Test();
    return t;
}
void m2(){
    cout<<"m2-Test"<<endl;
  }
};
int main(){
Test *t = Test::m1();
   t->m2();
   return 0;
}

答案 16 :(得分:0)

使用私有构造函数也可以提高面向域驱动设计的可读性/可维护性。 来自&#34; Microsoft .NET - 为企业构建应用程序,第2版&#34;:

var request = new OrderRequest(1234);

引用,&#34;这里有两个问题。首先,在查看代码时,很难猜出会发生什么 上。正在创建OrderRequest的实例,但为什么要使用哪些数据呢?什么是1234?这个 导致第二个问题:你违反了有界语境中普遍存在的语言。该 语言可能会这样说:客户可以发出订单请求并被允许 指定购买ID。如果是这种情况,这是获得新的OrderRequest实例的更好方法:&#34;

var request = OrderRequest.CreateForCustomer(1234);

,其中

private OrderRequest() { ... }

public OrderRequest CreateForCustomer (int customerId)
{
    var request = new OrderRequest();
    ...
    return request;
}

我并不是每个类都提倡这个,但对于上面的DDD场景,我认为防止直接创建新对象是完全合理的。

答案 17 :(得分:0)

除了更为人熟知的用途......

实现Method Object模式,我将其概括为:

  

“私有构造函数,公共静态方法”
  “实现对象,接口函数”

如果你想使用一个对象实现一个函数,并且该对象在进行一次性计算(通过方法调用)之外没有用处,那么你有一个Throwaway Object。您可以在静态方法中封装对象创建和方法调用,从而阻止这种常见的反模式:

z = new A(x,y).call();

...将其替换为(命名空间)函数调用:

z = A.f(x,y);

调用者永远不需要知道或关心你在内部使用一个对象,产生一个更干净的界面,防止物体上的垃圾徘徊或不正确地使用对象。

例如,如果您希望在方法foobarzork之间分解计算,例如共享状态而不必传入和传出多个值函数,您可以按如下方式实现:

class A {
  public static Z f(x, y) {
    A a = new A(x, y);
    a.foo();
    a.bar();
    return a.zork();
  }

  private A(X x, Y y) { /* ... */ };
}

此方法对象模式在 Smalltalk Best Practice Patterns ,Kent Beck,第34-37页中给出,其中它是重构模式的最后一步,结束:

  
      
  1. 将原始方法替换为创建新类实例的方法,使用原始方法的参数和接收器构造,并调用“compute”。
  2.   

这与此处的其他示例明显不同:类是可实例化的(与实用程序类不同),但实例是私有的(与工厂方法不同,包括单例等),并且可以存在于堆栈中,因为它们永远不会逃脱

这种模式在自下而上的OOP中非常有用,其中对象用于简化低级实现,但不一定是外部暴露,并且与自上而下的OOP形成对比,后者通常以高级别开始接口

答案 18 :(得分:0)

如果您想控制创建对象的实例的方式和时间(以及数量),有时会很有用。

其中,用于模式:

Singleton pattern
Builder pattern

答案 19 :(得分:0)

这是一个显而易见的原因:你想构建一个对象,但在构造函数中这样做(在接口方面)是不切实际的。

Factory示例非常明显,让我演示Named Constructor成语。

假设我有一个类Complex,它可以表示一个复数。

class Complex { public: Complex(double,double); .... };

问题是:构造函数是否需要实部和虚部,还是期望范数和角度(极坐标)?

我可以更改界面以使其更容易:

class Complex
{
public:
  static Complex Regular(double, double = 0.0f);
  static Complex Polar(double, double = 0.0f);
private:
  Complex(double, double);
}; // class Complex

这称为Named Constructor成语:只能通过明确说明我们希望使用哪个构造函数来从头构建类。

这是许多施工方法的特例。设计模式提供了许多构建对象的方法:BuilderFactoryAbstract Factory,...并且私有构造函数将确保用户得到适当的约束。

答案 20 :(得分:0)

您可能希望阻止类自由地实例化。以单件设计模式为例。为了保证唯一性,你不能让任何人创建它的实例: - )

答案 21 :(得分:0)

其中一个重要用途是在SingleTon类

class Person
{
   private Person()
   {
      //Its private, Hense cannot be Instantiated
   }

   public static Person GetInstance()
   {
       //return new instance of Person
       // In here I will be able to access private constructor
   }
};

它也适用,如果你的类只有静态方法。即没有人需要实例化你的班级

答案 22 :(得分:0)

Effective Java引用,你可以让一个私有构造函数的类有一个定义常量的实用程序类(作为静态最终字段)。

编辑:根据评论这可能只适用于Java,我不知道这个结构是否适用于其他OO语言(比如C ++))

如下例子:

public class Constants {
    private Contants():

    public static final int ADDRESS_UNIT = 32;
    ...
}

public class Constants { private Contants(): public static final int ADDRESS_UNIT = 32; ... }

EDIT_1 的: 同样,下面的解释适用于Java :(并参考书籍Effective Java

如下所示的实用程序类的实例化虽然没有害处,但却无法实现 任何目的,因为它们不是为了实例化而设计的。

例如,假设类Constants没有私有的构造函数。 像下面这样的代码块是有效的,但不能更好地传达意图 Constants类的用户

unit = (this.length)/new Constants().ADDRESS_UNIT;

与代码相比 unit = (this.length)/new Constants().ADDRESS_UNIT;

此外,我认为私有构造函数传达了常量的设计者的意图 (比如)上课更好。

如果没有构造函数,Java提供了一个默认的无参数公共构造函数 提供,如果你的意图是防止实例化,那么私有构造函数是 需要。

无法将顶级类标记为静态,甚至可以实例化最终类。

答案 23 :(得分:0)

实用程序类可以有私有构造函数。这些类的用户不应该能够实例化这些类:

public final class UtilityClass {
    private UtilityClass() {}

    public static utilityMethod1() {
        ...
    }
}