好友声明的反面
Opposite of friend declaration
假设我们有一个具有私有构造函数的 class,通过 friend
我们可以允许某些特定的 class(es) 仍然创建此 class 的对象:
class Foo
{
friend class Bar;
private:
Foo();
};
class Bar
{
Bar()
{
//create a Foo object
}
};
现在如果我想要 friend
的对立面怎么办,其中 Foo
看起来像这样:
class Foo
{
//enemy/foe??? class Bar; (if only)
public:
Foo();
};
然后 Bar
的任何方法都不能访问 Foo
构造函数/创建 Foo
的对象,但其他 classes 可以(因为它是 public
).
class Bar
{
Bar()
{
Foo foo; //compiler error
}
};
这样的构造是否可能,或者我是否坚持将 Foo
保密并为所有 class 添加好友?
这种东西是不存在的,而且是极其没有意义的。想象一下你有这样的情况:
class Foo
{
enemy class Bar;
public:
Foo() {}
};
class Bar
{
void evil() { Foo{}; }
};
没有什么能阻止 Bar
的实现者这样做:
class Bar
{
void evil() { do_evil(*this); }
};
void do_evil(Bar &self)
{
Foo{};
}
do_evil
不是 Bar
的成员(它是一个全局函数),所以它不是敌人。因此,可以轻松规避这种不友好。
C++中没有这样的概念。
Public 属性将始终是 public,但是您可以限制 Foo
的暴露,方法是使构造函数受保护,例如,仅对选定的 class 可见]es(尽管建议限制 friend
)。也许还可以将 Foo
作为 Bar2
的受保护 class,因为只有 Bar2
或其子代会实际使用它。
确实做不到,但也许下面的内容对你来说已经足够了:
template <typename T> struct Tag {};
class Foo
{
public:
template <typename T>
Foo(Tag<T>) {}
Foo(Tag<Bar>) = delete;
// ...
};
所以向 "creator" 询问 "identify" 本身。
class Bar
{
Bar()
{
Foo foo{Tag<Bar>{}}; //compiler error
// Foo foo{Tag<void>{}}; // valid as we can cheat about identity.
}
};
正如其他人已经说过的,你的愿望打破了封装的想法,因为你不能总是知道你的敌人是谁。
但是,还是有可能得到(几乎)你想要的:
#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"
}
};
假设我们有一个具有私有构造函数的 class,通过 friend
我们可以允许某些特定的 class(es) 仍然创建此 class 的对象:
class Foo
{
friend class Bar;
private:
Foo();
};
class Bar
{
Bar()
{
//create a Foo object
}
};
现在如果我想要 friend
的对立面怎么办,其中 Foo
看起来像这样:
class Foo
{
//enemy/foe??? class Bar; (if only)
public:
Foo();
};
然后 Bar
的任何方法都不能访问 Foo
构造函数/创建 Foo
的对象,但其他 classes 可以(因为它是 public
).
class Bar
{
Bar()
{
Foo foo; //compiler error
}
};
这样的构造是否可能,或者我是否坚持将 Foo
保密并为所有 class 添加好友?
这种东西是不存在的,而且是极其没有意义的。想象一下你有这样的情况:
class Foo
{
enemy class Bar;
public:
Foo() {}
};
class Bar
{
void evil() { Foo{}; }
};
没有什么能阻止 Bar
的实现者这样做:
class Bar
{
void evil() { do_evil(*this); }
};
void do_evil(Bar &self)
{
Foo{};
}
do_evil
不是 Bar
的成员(它是一个全局函数),所以它不是敌人。因此,可以轻松规避这种不友好。
C++中没有这样的概念。
Public 属性将始终是 public,但是您可以限制 Foo
的暴露,方法是使构造函数受保护,例如,仅对选定的 class 可见]es(尽管建议限制 friend
)。也许还可以将 Foo
作为 Bar2
的受保护 class,因为只有 Bar2
或其子代会实际使用它。
确实做不到,但也许下面的内容对你来说已经足够了:
template <typename T> struct Tag {};
class Foo
{
public:
template <typename T>
Foo(Tag<T>) {}
Foo(Tag<Bar>) = delete;
// ...
};
所以向 "creator" 询问 "identify" 本身。
class Bar
{
Bar()
{
Foo foo{Tag<Bar>{}}; //compiler error
// Foo foo{Tag<void>{}}; // valid as we can cheat about identity.
}
};
正如其他人已经说过的,你的愿望打破了封装的想法,因为你不能总是知道你的敌人是谁。
但是,还是有可能得到(几乎)你想要的:
#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"
}
};