Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opposite of friend declaration

Tags:

c++

c++17

friend

Say we have a class that has a private constructor, through friend we can allow some specific class(es) to still create objects of this class:

class Foo
{
 friend class Bar;
private:
  Foo();
};

class Bar
{
  Bar()
  {
    //create a Foo object
  }
};

Now what if I want the opposite of friend, where Foo looks like this:

class Foo
{
 //enemy/foe??? class Bar; (if only)
public:
  Foo();
};

And then no method of Bar can access the Foo constructor/ make an object of Foo but other classes can (because it's public).

class Bar
{
  Bar()
  {
    Foo foo; //compiler error
  }
};

Is such a construct possible or am I stuck with keeping Foo private and adding friends for all the classes?

like image 845
Hatted Rooster Avatar asked Oct 19 '18 12:10

Hatted Rooster


People also ask

Can we declare friend function as private?

A friend function can be declared in the private or public part of a class without changing its meaning. Friend functions are not called using objects of the class because they are not within the class's scope. Without the help of any object, the friend function can be invoked like a normal member function.

How do you declare a friend function?

The friend function is declared using the friend keyword inside the body of the class. Friend Function Syntax: class className { ... .. ... friend returnType functionName(arguments); ... .. ... }

Can constructor be friend?

sure it does. It should work, so there must be a specific syntactic problem in the OP's code, or maybe a misunderstanding regarding how friendliness works.

Can we define friend function in class?

friend functions A friend function is a function that isn't a member of a class but has access to the class's private and protected members. Friend functions aren't considered class members; they're normal external functions that are given special access privileges.


2 Answers

Such a thing does not exist, and it would be extremely pointless. Imagine you have a situation like this:

class Foo
{
  enemy class Bar;

public:
  Foo() {}
};

class Bar
{
  void evil() { Foo{}; }
};

Nothing prevents the implementor of Bar from doing this:

class Bar
{
  void evil() { do_evil(*this); }
};

void do_evil(Bar &self)
{
  Foo{};
}

do_evil is not a member of Bar (it's a global function), and so it's not an enemy. Such non-friendliness could therefore be trivially circumvented.

like image 192
Angew is no longer proud of SO Avatar answered Sep 29 '22 18:09

Angew is no longer proud of SO


It cannot be done really, but maybe following is enough for you:

template <typename T> struct Tag {};

class Foo
{
public:
    template <typename T>
    Foo(Tag<T>) {}

    Foo(Tag<Bar>) = delete;

    // ...
};

And so asking "creator" to "identify" itself.

class Bar
{
    Bar()
    {
        Foo foo{Tag<Bar>{}}; //compiler error

        // Foo foo{Tag<void>{}}; // valid as we can cheat about identity.
    }
};
like image 27
Jarod42 Avatar answered Sep 29 '22 17:09

Jarod42