Hatted Rooster
Hatted Rooster

Reputation: 36483

Opposite of friend declaration

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?

Upvotes: 6

Views: 596

Answers (4)

Handy999
Handy999

Reputation: 776

As it has already been sayed by others, your desire breaks the idea of encapsulation because you cannot always know who your enemies are.

But, still, there is a possibility to get (almost) what you want:

#include <type_traits>

struct enemy;  // We need a forward declaration of your enemy

struct my_class {

    // The access is done using a factory, where the caller has to tell
    // us his own name
    template <class T>
    struct make{
        static_assert(!std::is_same<T,enemy>::value,"you are my enemy.");
        friend T;
    private:
        my_class operator() () { return my_class{}; }
    };


private:
    my_class(); // This is the constructor we care about

};

struct no_enemy {
    void bar() {
        my_class a = my_class::make<no_enemy>{}();  // works
    }
};


struct enemy {
    void bar() {
        my_class b = my_class::make<enemy>{}();     // error: static_assert failed
        my_class c = my_class::make<no_enemy>{}();  // error: foo is "private"
    }
};

Upvotes: 0

Jarod42
Jarod42

Reputation: 217593

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.
    }
};

Upvotes: 1

Matthieu Brucher
Matthieu Brucher

Reputation: 22023

There is no such concept in C++.

Public attributes will always be public, but you can limit the exposure of Foo by making the constructor protected, for instance, and only visible for selected classes (although limiting friend is advised). Perhaps also make Foo as a protected class of Bar2 because only Bar2 or its children will actually use it.

Upvotes: 0

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.

Upvotes: 8

Related Questions