When Is a Private Constructor Not a Private Constructor

When is a private constructor not a private constructor?

The trick is in C++14 8.4.2/5 [dcl.fct.def.default]:

... A function is user-provided if it is user-declared and not explicitly defaulted or
deleted on its first declaration. ...

Which means that C's default constructor is actually not user-provided, because it was explicitly defaulted on its first declaration. As such, C has no user-provided constructors and is therefore an aggregate per 8.5.1/1 [dcl.init.aggr]:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

Why does a private base class constructor result in Implicit super constructor is not visible

if B extends A, B must have an access to an A constructor.

Keep in mind that a constructor always call super().
So here, the implicit parameterless constructor of B can't call the A constructor.

Why do we need a private constructor at all?

We can't instantiate more than one object at a time via private constructors.

No, we can. A private constructor only avoids instance creation outside the class. Therefore, you are responsible for deciding in which cases a new object should be created.

And as expected both the strings are being printed. Did I miss something?

You are creating a new instance every time the getInstance method is called. But your commented code contains a standard lazy initialization implementation of the singleton pattern. Uncomment these parts to see the difference.

Other singleton implementations you can look over here.

Use of a private constructor

It is a private constructor. This means that outside classes cannot create new instances using the default constructor.

A little more info

All Objects in Java have a default constructor:

public MyObject() {}

That is how you can have this class:

public class MyObject{}

and still be able to call:

MyObject mObj = new MyObject();

Private Constructors

Sometimes a developer may not want this default constructor to be visible. Adding any other constructor will nullify this constructor. This can either be a declared constructor with empty parameters (with any of the visibility modifiers) or it can be a different constructor all together.

In the case above, it is likely that one of the following models is followed:

  1. The Settings object is instantiated within the Settings class, and is where all the code is run (a common model for Java - where such a class would also contain a static main(String[] args) method).

  2. The Settings object has other, public constructors.

  3. The Settings object is a Singleton, whereby one static instance of the Settings Object is provided to Objects through an accessor method. For example:


public class MyObject {
private static MyObject instance;
private MyObject(){}//overrides the default constructor
public static MyObject sharedMyObject() {
if (instance == null)
instance = new MyObject();//calls the private constructor
return instance;
}
}

Issues related to declaration of private constructor in a class

Simple words, object or instance can't be created for that class.

As soon as, you write this statement below. For example

SomeClass c = new SomeClass(); // this will give an exception.

Basically, private constructors are used for making singleton classes.

why private constructor prevents object creation C++

To create an object in C++, a constructor needs to be called. If the constructor that needs to be invoked is not accessible, then it can't be called, and the object cannot be created.

The point of a private constructor is not preventing object construction. It is about controlling which code can access the constructor, and therefore limiting which code to create an object that is an instance of that class. A private constructor is accessible to all member functions (static or otherwise) of the class, and to all declared friends of the class (which may be individual functions, or other classes) - so any of those can create an instance of the class using a private constructor (assuming the constructor is defined).

If the constructor cannot be invoked, the object cannot be initialised. After all, the job of the constructor is to initialise the object. But if the constructor is inaccessible, then the object cannot be constructed, so it is not possible to have an uninitialised object.

Of course, there is nothing preventing the class from having multiple constructors with different access controls (private, protected, and public). A class with a public constructor can be constructed, using that constructor, by any code. But any attempt to use a private constructor (by a non-member non-friend) will still be rejected. So access control allows the (developer of the) class some measure of control over how an instance is constructed.

Not defining (i.e. not implementing) a constructor does prevent construction of an object. If that constructor is private, the compiler will reject an attempt to call it (unless the function attempting to create an instance is a member or a friend, as above). For members and friends of the class, the compiler will permit access to the constructor, but (in a typical compile-then-link toolchain) the linker will not build an executable, since it cannot resolve a call to a function that is not defined. Using the technique of marking a constructor private and not defining it is a common way of preventing code from constructing an instance of the class (by either preventing the code from compiling, or preventing it from running).

Do constructors always have to be public?

No, Constructors can be public, private, protected or default(no access modifier at all).

Making something private doesn't mean nobody can access it. It just means that nobody outside the class can access it. So private constructor is useful too.

One of the use of private constructor is to serve singleton classes. A singleton class is one which limits the number of objects creation to one. Using private constructor we can ensure that no more than one object can be created at a time.

Example -

public class Database {

private static Database singleObject;
private int record;
private String name;

private Database(String n) {
name = n;
record = 0;
}

public static synchronized Database getInstance(String n) {
if (singleObject == null) {
singleObject = new Database(n);
}

return singleObject;
}

public void doSomething() {
System.out.println("Hello StackOverflow.");
}

public String getName() {
return name;
}
}

More information about access modifiers.

Why is private constructor still visible in case class?

Make the method A.apply(Seq[Int]) private too

A.scala

package X

object A {
def apply(x: Int): A = A(Seq(x))
private def apply(s: Seq[Int]): A = new A(s) // make explicit and private instead of auto-generated and public
}

case class A private(private val s: Seq[Int])

B.scala

package Y

import X.A

class B {
//val b = A(Seq.empty) // doesn't compile
}

Here the line val b = A(Seq.empty) produces error

Error: polymorphic expression cannot be instantiated to expected type;
found : [A]Seq[A]
required: Int

i.e. the method A.apply(Seq[Int]) is not visible from B.

When do we need a private constructor in C++?

There are a few scenarios for having private constructors:

  1. Restricting object creation for all but friends; in this case all constructors have to be private

    class A
    {
    private:
    A () {}
    public:
    // other accessible methods
    friend class B;
    };

    class B
    {
    public:
    A* Create_A () { return new A; } // creation rights only with `B`
    };
  2. Restricting certain type of constructor (i.e. copy constructor, default constructor). e.g. std::fstream doesn't allow copying by such inaccessible constructor

    class A
    {
    public:
    A();
    A(int);
    private:
    A(const A&); // C++03: Even `friend`s can't use this
    A(const A&) = delete; // C++11: making `private` doesn't matter
    };
  3. To have a common delegate constructor, which is not supposed to be exposed to the outer world:

    class A
    {
    private:
    int x_;
    A (const int x) : x_(x) {} // common delegate; but within limits of `A`
    public:
    A (const B& b) : A(b.x_) {}
    A (const C& c) : A(c.foo()) {}
    };
  4. For singleton patterns when the singleton class is not inheritible (if it's inheritible then use a protected constructor)

    class Singleton
    {
    public:
    static Singleton& getInstance() {
    Singleton object; // lazy initialization or use `new` & null-check
    return object;
    }
    private:
    Singleton() {} // make `protected` for further inheritance
    Singleton(const Singleton&); // inaccessible
    Singleton& operator=(const Singleton&); // inaccessible
    };

How to make sure instance of a class with a private constructor can not be created from outside of the class using Reflection?

There are several ways to prevent the creation - but it is hard to tell which one is appropriate for your use-case:

  1. Throw an exception in the constructor

    You can either unconditionally throw an exception - making it (near) impossible to instantiate an instance - or only throw under certain conditions.

    Some conditions can be:

    • Inspecting the caller - using StackWalker for example.
    • Passing a "secret" passphrase to the constructor. JMH does this for example.
  2. Use Java Modules.

    As other modules can't deeply reflect into other named modules, Constructor.setAccessible will not work on your class outside of your own module.

    Of course this restriction doesn't apply to your own module - but you should be able to control your own module ;).

  3. Install a SecurityManager.

    Prevents Constructor.setAccessible from returning successfully.

    But the security manager is deprecated for removal, so I can't recommend it's use.

Note: Most of those solutions can be circumvented in some way. And it is sometimes possible to add additional defenses against that. But at the end, it'll become a game of cat and mouse.



Related Topics



Leave a reply



Submit