What is the use of making constructor private in a class?
为什么我们要在类中使构造函数私有化?因为我们总是需要将构造函数公开。
您可能需要私有构造函数的一些原因:
通过提供一个私有的构造函数,可以防止类实例在这个类之外的任何地方被创建。提供这种构造函数有几个用例。
a.类实例是在
1 2 3 4 5 6 7 8 | class MyClass() { private: MyClass() { } public: static MyClass * CreateInstance() { return new MyClass(); } }; |
B.你的班是单人的。这意味着程序中不存在类的多个实例。
1 2 3 4 5 6 7 8 9 10 11 12 | class MyClass() { private: MyClass() { } public: MyClass & Instance() { static MyClass * aGlobalInst = new MyClass(); return *aGlobalInst; } }; |
C.(仅适用于即将到来的C++ 0x标准),您有几个构造函数。其中一部分被宣布为
1 2 3 4 5 6 7 8 | class MyClass { public: MyClass() : MyClass(2010, 1, 1) { } private: MyClass(int theYear, int theMonth, int theDay) { /* do real work */ } }; |
d.您希望限制对象复制(例如,因为使用共享资源):
1 2 3 4 5 6 7 | class MyClass { SharedResource * myResource; private: MyClass(const MyClass & theOriginal) { } }; |
你的课是实用课。也就是说,它只包含
离开"后门",允许另一个朋友类/函数以用户禁止的方式构造对象。想到的一个例子是构建迭代器(C++)的容器:
1 2 3 | Iterator Container::begin() { return Iterator(this->beginPtr_); } // Iterator(pointer_type p) constructor is private, // and Container is a friend of Iterator. |
每个人都被困在单身的事情上,哇。
其他事项:
- 阻止人们在堆栈上创建类;创建私有的构造函数,并且只通过工厂方法返回指针。
- 阻止创建类的副本(私有副本构造函数)
这对于包含公共代码的构造函数非常有用;其他构造函数可以使用"this(…);"表示法调用私有构造函数。通过在私有(或受保护)构造函数中生成公共初始化代码,您还可以明确地表明,它只在构造期间调用,如果它只是一个方法,则不是这样:
1 2 3 4 5 6 7 8 | public class Point { public Point() { this(0,0); // call common constructor } private Point(int x,int y) { m_x = x; m_y = y; } }; |
有些情况下,您可能不想使用公共构造函数;例如,如果您想使用单例类。
如果您正在编写第三方使用的程序集,则可能有许多内部类,您只希望由程序集创建,而不是由程序集的用户实例化。
这样可以确保(具有私有构造函数的类)控制如何调用构造函数。
例如:类上的静态工厂方法可以返回对象,因为工厂方法选择分配对象(例如,单例工厂)。
我们也可以有私有的构造函数,强制特定类创建对象仅限(出于安全原因)。
一种方法是通过一个朋友班。C++示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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的构造函数。
下面是私有构造函数的一些用法:
如果它是私有的,那么您不能调用它=>您不能实例化类。在某些情况下很有用,比如单件。
这里有一个讨论和更多的例子。
如果不希望用户创建此类的实例或创建继承此类的类,如
构造器对于某些目的是私有的,例如需要实现单例或限制类的对象数。例如,在单例实现中,我们必须使构造函数私有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #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,请使用以下命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #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 } |
谢谢
可以有多个构造函数。C++提供默认构造函数和缺省复制构造函数,如果不显式提供构造函数。假设您有一个类,它只能使用一些参数化的构造函数来构造。也许它初始化了变量。如果用户在没有该构造函数的情况下使用这个类,那么它们将不会导致任何问题的结束。一个好的一般规则:如果默认实现无效,则将默认和复制构造函数都设为私有,并且不提供实现:
1 2 3 4 5 6 7 8 9 | class C { public: C(int x); private: C(); C(const C &); }; |
使用编译器可以防止用户使用带有无效默认构造函数的对象。
我看到你提出的一个问题也在解决同一个问题。
简单地说,如果您不想让其他人创建实例,那么将构造器保持在一个有限的范围内。实际应用(示例)是单例模式。
您不应该将构造函数设置为私有的。时期。使其受保护,以便在需要时扩展类。
编辑:不管你投多少反对票,我都支持你的观点。您切断了代码未来开发的潜力。如果其他用户或程序员真的决定扩展类,那么他们只需将构造函数更改为受源代码或字节码保护的。除了让他们的生活更艰难之外,你什么也没做。在构造函数的注释中包含一个警告,并将其保留。
如果它是一个实用程序类,那么更简单、更正确、更优雅的解决方案是将整个类标记为"静态final",以防止扩展。仅仅将构造函数标记为私有并没有任何好处;真正确定的用户可能总是使用反射来获取构造函数。
有效用途:- 一个很好的使用EDOCX1[0]构造函数将强制使用静态工厂方法,允许您限制实例化或池的重用昂贵的资源(数据库连接,本地资源)。
- 单件(通常不是很好的练习,但有时是必要的)
除了众所周知的用途…
要实现方法对象模式,我将总结为:
"Private constructor, public static method"
"Object for implementation, function for interface"
如果您想使用对象实现一个函数,而该对象在执行一次性计算(通过方法调用)之外没有用处,那么您就有了一个一次性对象。您可以用静态方法封装对象创建和方法调用,以防止这种常见的反模式:
1 | z = new A(x,y).call(); |
…将其替换为(命名空间)函数调用:
1 | z = A.f(x,y); |
调用方永远不需要知道或关心您在内部使用对象,生成更干净的接口,并防止对象周围出现垃圾或对象的错误使用。
例如,如果要在方法
1 2 3 4 5 6 7 8 9 10 | 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最佳实践模式中给出,Kent Beck,第34-37页,其中是重构模式的最后一步,结束于:
Replace the original method with one that creates an instance of the new class, constructed with the parameters and receiver of the original method, and invokes"compute".
这与这里的其他示例有很大的不同:类是可实例化的(与实用程序类不同),但是实例是私有的(与工厂方法不同,包括单例等),并且可以在堆栈上生存,因为它们永远不会逸出。
这种模式在自下而上的OOP中非常有用,在这种OOP中,对象用于简化低级实现,但不一定暴露在外部,与通常呈现并以高级接口开头的自上而下的OOP形成对比。
在域驱动的设计中,私有构造函数的使用还可以提高可读性/可维护性。来自"Microsoft.NET-企业级存档应用程序,第2版":
1 | var request = new OrderRequest(1234); |
引述,"这里有两个问题。首先,当查看代码时,很难猜出发生了什么。在。正在创建orderrequest的一个实例,但为什么要创建并使用哪些数据?1234是多少?这个导致第二个问题:您违反了有界上下文中无处不在的语言。这个语言可能会这样说:客户可以发出订单请求,并允许指定采购ID。如果是这种情况,下面是获取新订单请求实例的更好方法:"
1 | var request = OrderRequest.CreateForCustomer(1234); |
哪里
1 2 3 4 5 6 7 8 | private OrderRequest() { ... } public OrderRequest CreateForCustomer (int customerId) { var request = new OrderRequest(); ... return request; } |
我不是在为每一个类都提倡这样做,但是对于上面的DDD场景,我认为阻止直接创建一个新对象是完全有意义的。
其中一个重要用途是在singleton类中
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 } }; |
如果类只有静态方法,那么它也适用。也就是说没有人需要实例化你的类
引用有效的Java,可以使用一个具有私有构造函数的类来定义定义常量的实用工具类(作为静态最终字段)。
(编辑:根据评论,这是一个仅适用于Java的东西,我不知道这个构造是否适用于其他OO语言(如C++)。
示例如下:
ZZU1〔2〕
编辑1:同样,下面的解释在Java中是适用的:(参考书,有效的Java)
像下面这样的实用程序类的实例虽然不有害,但不起作用任何目的,因为它们不是为实例化而设计的。
例如,假设没有类常量的私有构造函数。下面这样的代码块是有效的,但不能更好地表达常量类的用户
ZZU1〔3〕
与类似代码相比
ZZU1〔4〕
另外,我认为一个私有的构造函数传达了常量设计者的意图。(说)上课更好。
如果没有构造函数,Java提供默认的无参数公共构造函数。如果您的目的是防止实例化,那么私有构造函数是需要。
不能将顶级类标记为静态,甚至可以实例化最终类。
如果要控制对象实例的创建方式和时间(以及创建的实例数),有时会很有用。
除其他外,用于模式:
1 2 | Singleton pattern Builder pattern |
您可能希望防止类被自由地实例化。以单例设计模式为例。为了保证唯一性,您不能让任何人创建它的实例:-)
这确实是一个显而易见的原因:您希望构建一个对象,但在构造函数中(从接口的角度)进行此操作是不实际的。
假设我有一个类
1 | class Complex { public: Complex(double,double); .... }; |
问题是:构造器期望的是实部和虚部,还是期望的是范数和角度(极坐标)?
我可以更改界面以使其更简单:
1 2 3 4 5 6 7 8 | class Complex { public: static Complex Regular(double, double = 0.0f); static Complex Polar(double, double = 0.0f); private: Complex(double, double); }; // class Complex |
这被称为
这是许多施工方法的特例。设计模式提供了许多构建对象的方法:
实用程序类可以有私有构造函数。类的用户不应该能够实例化这些类:
1 2 3 4 5 6 7 | public final class UtilityClass { private UtilityClass() {} public static utilityMethod1() { ... } } |