Какой смысл делать конструктор private в классе?

Почему мы должны сделать конструктор приватным в классе? Поскольку нам всегда нужно, чтобы конструктор был общедоступным.

23 ответов


некоторые причины, по которым вам может понадобиться частный конструктор:

  1. конструктор может быть доступен только из статический метод фабрики внутри самого класса. Синглтон также может принадлежать к этой категории.
  2. служебный класс, который содержит только статические методы.

предоставляя частный конструктор, вы предотвращаете создание экземпляров класса в любом месте, кроме этого самого класса. Существует несколько вариантов использования для предоставления такого конструктора.

А. экземпляры класса создаются в static метод. The static метод затем объявляется как public.

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

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

Б. свой класс синглтон. Это означает, что в классе существует не более одного экземпляра программа.

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) { }
};

е. ваш класс служебный класс. Это означает, что он содержит только static членов. В этом случае экземпляр объекта должен быть создан в программе.


оставить "заднюю дверь", которая позволяет другому классу/функции друга построить объект способом, запрещенным для пользователя. Примером, который приходит на ум, будет контейнер, создающий итератор (C++):

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

все застряли на синглтоне, вау.

другие вещи:

  • остановите людей от создания вашего класса в стеке; сделайте частные конструкторы и только возвращайте указатели с помощью Заводского метода.
  • предотвращение создания копий класса (конструктор частной копии)

Это может быть очень полезно для конструктора, который содержит общий код; закрытые конструкторы другие конструкторы, с помощью этого(...);' нотация. Делая общий код инициализации в частном (или защищенном) конструкторе, вы также ясно даете понять, что он вызывается только во время построения, что не так, если бы это был просто метод:

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

есть несколько случаев, когда вы не хотите использовать открытый конструктор; например, если вы хотите одноэлементный класс.

Если вы пишете сборку, используемую третьими сторонами, может быть несколько внутренних классов, которые вы хотите создать только своей сборкой, а не создавать экземпляры пользователями вашей сборки.


Это гарантирует, что вы (класс с частным конструктором) контролируете, как вызывается contructor.

пример: статический заводской метод в классе может возвращать объекты, поскольку заводской метод выбирает их для выделения (например, одноэлементная фабрика).


мы также можем иметь собственный конструктор, для создания объекта определенным классом только(по соображениям безопасности).

один из способов сделать это-иметь класс друга.

в 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.


Если это личное, то вы не можете назвать его ==> вы не можете создать экземпляр класса. Полезно в некоторых случаях, как синглтон.

там есть Обсуждение и еще несколько примеров здесь.


Я видел вопрос от вас по той же проблеме.

просто, если вы не хотите позволять другим создавать экземпляры, то держите constuctor в ограниченной области. Практическое применение (пример) - это одноэлементный шаблон.


вы не стоит сделать конструктор приватным. Период. Сделайте его защищенным, чтобы вы могли расширить класс, если вам нужно.

Edit: я стою на этом, независимо от того, сколько downvotes вы бросаете на это. Вы лишаете код возможности дальнейшего развития. Если другие пользователи или программисты действительно намерены расширить класс, они просто изменят конструктор на protected in source или bytecode. У вас будет не достиг ничего, кроме того, чтобы сделать их жизнь немного сложнее. Включите предупреждение в комментарии вашего конструктора и оставьте его на этом.

если это класс утилиты, то более простым, правильным и элегантным решением является пометка всего класса "static final" для предотвращения расширения. Не стоит просто отмечать конструктор private; действительно определенный пользователь всегда может использовать отражение для получения конструктора.

действующий использует:

  • одно хорошее использование protected конструктор должен принудительно использовать static заводские методы, которые позволяют ограничение создания экземпляра или пула и повторного использования дорогие ресурсы (подключения к БД, native resources).
  • Singletons (обычно не хорошая практика, но иногда необходимо)

конструктор является частным для некоторых целей, например, когда вам нужно реализовать singleton или ограничить количество объектов класса. Например, в реализации singleton мы должны сделать конструктор private

#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 &);
};

используйте компилятор, чтобы запретить пользователям использовать объект с недопустимыми конструкторами по умолчанию.



Если вы не хотите, чтобы пользователи создавали экземпляры этого класса или создавали класс, наследующий этот класс, например java.lang.math, вся функция в этом пакете -static, все функции могут быть вызваны без создания экземпляра math, поэтому конструктор объявляется как статический.


цитирую Эффективная Java, вы можете иметь класс с частным конструктором, чтобы иметь класс утилиты, который определяет константы (как статические конечные поля).

( EDIT: согласно комментарию это то, что может быть применимо только с Java, я не знаю, применима ли эта конструкция/необходима в других языках OO (скажем, c++))

пример, как показано ниже:

EDIT_1: Again, below explanation is applicable in Java : (and referring from the book, Effective Java)

An instantiation of utility class like the one below ,though not harmful, doesn't serve any purpose since they are not designed to be instantiated.

For example, say there is no private Constructor for class Constants. A code chunk like below is valid but doesn't better convey intention of the user of Constants class

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

в отличие от кода

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

также я думаю, что частный конструктор передает намерение дизайнера константы класс лучше.

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, ... и частный конструктор гарантирует, что пользователь правильно ограничен.


В дополнение к более известным использует...

для реализации Метод Объекта шаблон, который я бы суммировал как:

"частный конструктор, публичный статический метод"
"Объект для реализации, функция для интерфейса"

если вы хотите реализовать функцию с помощью объекта, и объект не полезен вне выполнения одноразового вычисления( с помощью вызова метода), то у вас есть одноразовые Объект. Вы можете инкапсулировать создание объекта и вызов метода в статический метод, предотвращая этот общий анти-шаблон:

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

...замена его вызовом функции (namespaced):

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 Лучшие Образцы Практики, Кент Бек, страницы 34-37, где это последний шаг рефакторинга, заканчивающийся:

  1. заменить оригинальный метод, который создает экземпляр нового класса, построен с параметрами и приемником исходного метода и вызывает "compute".

это существенно отличается от других примеров здесь: класс инстанцируемая (в отличие от служебного класса), но случаи частные (в отличие от фабричных методов, включая одиночек и т. д.), и могут жить на стеке, так как они никогда не убегают.

эта картина очень полезна в дн-вверх ООП, где объекты использованы для того чтобы упростить низкоуровневое реализация, но не обязательно подвергается внешнему воздействию и контрастирует с нисходящим ООП, который часто представлен и начинается с интерфейсов высокого уровня.


иногда полезно, если вы хотите контролировать, как и когда (и сколько) экземпляров объекта создаются.

среди прочего, используется в шаблонах:

Singleton pattern
Builder pattern

при использовании частных конструкторов также можно повысить читаемость / ремонтопригодность перед лицом доменного дизайна. От "Microsoft .Нетто - Architecing приложений для предприятия, 2-е издание":

var request = new OrderRequest(1234);

цитирую: "здесь есть две проблемы. Во-первых, глядя на код, трудно догадаться, что происходит на. Создается экземпляр OrderRequest, но почему и с помощью каких данных? Что 1234? Этот приводит ко второй проблеме: вы нарушаете вездесущий язык ограниченного контекста. Этот язык, вероятно, говорит что-то вроде этого: клиент может оформить запрос на заказ и может укажите идентификатор покупки. Если это так, вот лучший способ получить новый экземпляр OrderRequest:"

var request = OrderRequest.CreateForCustomer(1234);

здесь

private OrderRequest() { ... }

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

Я не выступаю за это для каждого отдельного класса, но для вышеупомянутого сценария DDD я думаю, что имеет смысл предотвратить прямое создание нового объекта.