14

How can I restrict the instantiation of a class from only within a specific class?

I don't want to restrict it within a single file, so anonymous namespace is not an option for me.

Please note that I want to make the declaration of the to-be-restricted class visible to the entire world, just that only one specific candidate from the entire world can only instantiate it.

How can I achieve this?

Mariners
  • 499
  • 8
  • 18
  • 4
    Making that solitary class a `friend` in combination with `private` constructor of non-publicly constructable class, should work. – Algirdas Preidžius May 29 '17 at 16:36
  • " I want to make the declaration of the to-be-restricted class visible to the entire world, just that only one specific candidate from the entire world can only instantiate and access it" Then, why show it if you can't touch it? Am I missing something? – zdf May 29 '17 at 16:37
  • Do you want a Singleton pattern by any chance? Instantiate it once and use one instance for everything? – dage5 May 29 '17 at 16:38
  • 2
    Abstract factory pattern probably. –  May 29 '17 at 16:41
  • @ZDF Not being able to create instances of class X isn't the same as not being able to touch instances of X. Even if you can't instantiate some class, you can modify the state of the, already created, objects via the use of methods. – Algirdas Preidžius May 29 '17 at 16:42
  • @ZDF: Well that is because the to-be-restricted class would use a framework in my application which is usable by anyone and everyone and I happen to be just one of them to use it my one legacy framework. So, by dependency I am obliged to make it visible but I don't want any other framework apart from my legacy one to be able to access it. I will expose some API's to use the functionalities (owned by some other framework not under my control) in the to-be-restricted class. – Mariners May 29 '17 at 16:42
  • @AlgirdasPreidžius: Are you suggesting to make everything private in the to-be-restricted class and make the solitary-accessible-class a friend of it? – Mariners May 29 '17 at 16:44
  • 1
    @Mariners No, I didn't suggest that. Where did you read that I was suggesting to make _everything_ `private`? What I suggested was: _`private` constructor_, which is exactly what the top answer suggested, with an example. – Algirdas Preidžius May 29 '17 at 16:48
  • @AlgirdasPreidžius: Right. My bad. I apologise. I meant the _constructor_ only while saying _everything_ _private_. – Mariners May 29 '17 at 16:50
  • @AlgirdasPreidžius You said: "you can modify the state of the, already created, objects via the use of methods" OP said: "only one specific candidate from the entire world can only instantiate **and access it**". In other words he needs exclusive access to restricted class (not object). Maybe my English is the problem. – zdf May 29 '17 at 17:03
  • @ZDF Oh, I skimmed that paragraph, and didn't notice that part, because I read it as an elaboration of _How can I restrict the instantiation of a class from only within a specific class?_ Which only mentions instantiation. – Algirdas Preidžius May 29 '17 at 19:29

2 Answers2

15

Use friends! Making a class Foo a friend of a class Bar means that Foo can access Bar's private members. If you make the constructor(s) private, only Foo will be able to create an instance of Bar.

struct restricted_t {
    friend struct allowed_t; // allow 'allowed_t' to access my private members
private:
    // nobody can construct me (except for my friends of course)
    restricted_t() = default;
};

struct allowed_t {
    restricted_t yes; // ok
};

struct not_allowed_t {
    restricted_t no; // not ok
};

int main() {
    allowed_t a; // ok, can access constructor
    not_allowed_t b; // error, constructor is private
}
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
9

You could adopt the passkey pattern (borrowing from Rakete1111's example):

class pass_key { friend class allowed_t; pass_key() {} };

struct restricted_t
{
  restricted_t(pass_key);
};

class allowed_t
{
public:
  allowed_t() : yes(pass_key()) {}  // ok, allowed_t is a friend of pass_key

private:
  restricted_t yes;
};

class not_allowed_t
{
public:
  not_allowed_t() : no(pass_key()) {}  // not ok, pass_key() is private

private:
  restricted_t no;
};

int main()
{
  allowed_t a;     // OK, can access constructor
  not_allowed_t b; // ERROR, only a friend of the key
                   // class has access to the restricted
                   // constructor
}

The pattern allows a more fine-granular access-control than making restricted_t a friend of allowed_t and avoids complicated proxying patterns.

manlio
  • 18,345
  • 14
  • 76
  • 126
  • This is a nice solution. Thanks a lot :). – Mariners May 30 '17 at 16:42
  • @Mariners You're welcome. Also take a look at [Matthieu's description](https://stackoverflow.com/a/3218920/3235496) of the pattern for the implementation details. – manlio May 30 '17 at 17:22