Reputation: 36483
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
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
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
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
Reputation: 171127
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