Answers:
您可能需要私有构造函数的一些原因:
final
类级别。由于这个原因,放置私有构造函数几乎没有用。
final
。这就是Sun为String类所做的事情,是不应该扩展的合理的API块。
通过提供私有构造函数,可以防止在此类之外的任何地方创建类实例。提供这种构造函数有几种用例。
答:您的类实例是在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.(仅适用于即将到来的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) { }
};
E.您的课程是实用程序课程。这意味着,它仅包含static
成员。在这种情况下,程序中永远都不能创建对象实例。
留下一个“后门”,该后门允许另一个朋友类/函数以用户禁止的方式构造对象。我想到的一个例子是构造迭代器(C ++)的容器:
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
friend
在不需要的地方使用它-并且在很多情况下,这是个坏主意。可悲的是,该消息已经收到了太多好评,许多开发人员对语言的了解还不够好,以至于无法理解偶尔使用friend
不仅可以接受,而且更可取。您的例子就是这种情况。故意的强耦合不是犯罪,这是设计决定。
所有人都被单例卡住了,哇。
其他事情:
这样可以确保您(带有私有构造函数的类)控制如何调用构造函数。
一个示例:类上的静态工厂方法可以在工厂方法选择分配对象时返回对象(例如,单例工厂)。
我们还可以使用私有构造函数,以仅通过特定类来创建对象(出于安全原因)。
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的构造方法。
以下是private构造函数的一些用法:
我看到您有一个问题要解决。
简而言之,如果您不想允许其他人创建实例,则将构造器限制在有限范围内。实际应用(一个示例)是单例模式。
您不应该将构造函数设为私有。期。使其受到保护,因此可以根据需要扩展类。
编辑:无论您投多少票,我都支持。 您正在切断代码将来的开发潜力。如果其他用户或程序员确实确定要扩展该类,则只需将构造函数更改为源代码或字节码中的protected。除了使他们的生活更加艰难之外,您将一事无成。在构造函数的注释中包含警告,然后保留该警告。
如果是实用程序类,则更简单,更正确,更优雅的解决方案是将整个类标记为“ static final”以防止扩展。仅仅将构造函数标记为私有并没有任何好处。真正确定的用户可能总是使用反射来获取构造函数。
protected
构造函数的一个很好的用途是强制使用静态工厂方法,该方法允许您限制实例化或池化和重用昂贵的资源(数据库连接,本机资源)。构造函数出于某些目的是私有的,例如当您需要实现单例或限制类的对象数时。例如在单例实现中,我们必须将构造函数设为私有
#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
}
谢谢
您可以有多个构造函数。如果您未明确提供C ++,则会提供一个默认构造函数和一个默认副本构造函数。假设您有一个只能使用某些参数化构造函数构造的类。也许是初始化变量。如果用户然后在没有该构造函数的情况下使用此类,则他们将不会引起任何问题。一个很好的通用规则:如果默认实现无效,则将default和copy构造函数设为私有,并且不提供实现:
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
使用编译器可防止用户将对象与无效的默认构造函数一起使用。
引用Effective Java,您可以拥有一个带有私有构造函数的类,以拥有一个定义常量(作为静态final字段)的实用程序类。
(编辑:根据评论,这可能仅适用于Java,但我不知道此构造是否适用于/需要其他OO语言(例如C ++))
一个例子如下:
public class Constants {
private Contants():
public static final int ADDRESS_UNIT = 32;
...
}
EDIT_1:同样,以下解释适用于Java :(并参考《Effective Java》一书)
如下所示的实用程序类的实例,虽然无害,但没有任何作用,因为它们不是设计成实例化的。
例如,说没有常量类的私有构造函数。如下所示的代码块是有效的,但不能更好地传达Constants类用户的意图
unit = (this.length)/new Constants().ADDRESS_UNIT;
与类似的代码相反
unit = (this.length)/Constants.ADDRESS_UNIT;
另外,我认为私有构造函数可以 更好地传达Constants(例如)类的设计者的意图。
如果没有提供构造函数,Java将提供默认的无参数公共构造函数,并且如果您打算防止实例化,则需要一个私有构造函数。
不能将顶级类标记为静态,甚至可以实例化最后一类。
实用程序类可以具有私有构造函数。类的用户应该不能实例化这些类:
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
重要的用途之一是在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
}
};
如果您的类只有静态方法,则它也适用。即没有人需要实例化您的课程
这确实是一个显而易见的原因:您想要构建一个对象,但是在构造函数中(就接口而言)这样做是不实际的。
这个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
成语:只能通过明确说明我们希望使用哪个构造函数来从头开始构建该类。
这是许多构造方法的特例。设计模式提供了很好的一些方法来构建物体:Builder
,Factory
,Abstract Factory
,...和私人构造函数将确保用户正确的约束。
除了更知名的用途之外...
要实现方法对象模式,我将其总结为:
“私有构造函数,公共静态方法”
“实现的对象,接口的功能”
如果要使用对象实现功能,并且该对象在进行一次性计算(通过方法调用)之外没有用,那么您就有一个Throwaway Object。您可以将对象创建和方法调用封装在静态方法中,以防止出现这种常见的反模式:
z = new A(x,y).call();
…替换为(命名空间)函数调用:
z = A.f(x,y);
调用者永远不需要知道或关心您在内部使用对象,产生更清洁的界面以及防止对象周围产生垃圾或对象的错误使用。
例如,如果您想通过方法foo
,bar
和分解计算zork
,例如共享状态而不必在函数中传入和传出许多值,则可以按以下方式实现它:
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页中给出,该模式是重构模式的最后一步,结束于:
- 用原始方法替换原始方法,该方法创建新类的实例,该实例由原始方法的参数和接收器构造,并调用“计算”。
这与这里的其他示例有很大的不同:该类是可实例化的(不同于实用程序类),但是实例是私有的(与工厂方法不同,包括单例等),并且可以存在于堆栈中,因为它们永不转义。
这种模式在自下而上的OOP中非常有用,在自下而上的OOP中,对象用于简化低级别的实现,但不一定在外部公开,并且与经常出现并从高级接口开始的自上而下的OOP形成对比。
面对域驱动的设计,使用私有构造函数还可以提高可读性/可维护性。摘自“ Microsoft .NET-企业归档应用程序,第二版”:
var request = new OrderRequest(1234);
引用:“这里有两个问题。首先,在查看代码时,几乎无法猜测正在发生什么。正在创建一个OrderRequest实例,但是为什么和使用哪些数据?什么是1234?这导致了第二个问题:您违反了有界上下文的普遍语言,该语言可能会说像这样:客户可以发出订单请求并被允许指定购买ID。如果是这种情况,这是一种获取新OrderRequest实例的更好方法:“
var request = OrderRequest.CreateForCustomer(1234);
哪里
private OrderRequest() { ... }
public OrderRequest CreateForCustomer (int customerId)
{
var request = new OrderRequest();
...
return request;
}
我并不是为每个类都提倡这样做,但是对于上述DDD场景,我认为防止直接创建新对象是很有意义的。