有没有办法让所有派生的 类 成为彼此的朋友?
Is there a way to make all derived classes friends of one another?
如果是这样,这在什么情况下可能有用?
或者(我想是这样的),为什么它绝对没用? (还有什么其他方法本质上涵盖了这种友谊所提供的能力,而且是以一种更安全、更少泄漏的方式?)
当时我几乎认为我需要这样的东西。我最终采用了完全不同的设计,使所有 class 成员都静态化。不过我还是很好奇。
Is there a way to make all derived classes friends of one another?
该语言不提供任何机制来在基 class 中指定类似的东西。您必须在从基础 class.
继承的每个 class 中提供友元声明
我无法提出任何更积极的建议,因为我不知道您要解决的问题。
在评论中,您说:
In my case, I needed to access sibling methods, so if B
and C
derive from A
, I needed to call B::foo()
from C::foo()
. In my case these classes encapsulate different algorithms (so the Strategy pattern comes to mind...) but sometimes one algorithm would use a substantial portion of another algorithm. Yet, it didn't seem correct to derive C
from B
, because C
doesn't really have an "is-a" relationship with B
.
如果 C
与 B
没有 "is-a" 关系,但 C::foo()
以某种方式需要调用 B::foo()
,这表明我B::foo()
只能使用 B
和 C
共有的数据。在那种情况下,应该可以将代码分解为非成员函数,然后从 B::foo()
和 C::foo()
.
中使用它
更改依赖于:
B::foo()
^
|
C::foo()
至
<some namespace>::foo()
^
|
+-------+---------+
| |
B::foo() C::foo()
C++ 只给了你两种命名朋友的方法:
friend class C; // a specific class
template <typename T>
friend class S; // friend the class template S
无法在其中插入元函数,假设看起来像这样:
template <typename T>
friend enable_if_t<std::is_base_of<Base, T>::value, T>;
但我想如果你对可怕的黑客行为持开放态度(这句话应该被解释为永远不要这样做,请上帝不,但这至少有点有趣),你可以简单地将所有派生类型实现为显式一些模板的专业化。
struct Base { ... };
template <typename > class Derived;
struct A_tag { };
template <>
class Derived<A_tag> : Base {
template <typename T>
friend class Derived;
...
};
using A = Derived<A_tag>;
如果我们对B
、C
等做类似的事情,那么A
、B
和C
都是朋友-因为在引擎盖下它们实际上是 Derived<A_tag>
、Derived<B_tag>
和 Derived<C_tag>
,因此 friend class 模板语句涵盖了所有这些。
不完全是 friend
,但您可以使用 Passkey pattern
的某些变体来限制访问
如果您在您的基地 class 中创建受保护的内部密钥 class。然后,任何派生的 classes 都可以通过要求将密钥作为参数来限制对兄弟姐妹的访问:
class A {
protected:
class Passkey {};
};
class B : public A {
public:
void someProtectedFunction(Passkey) {};
};
class C : public A {
public:
void somePublicFunction() {
B b;
b.someProtectedFunction(A::Passkey{});
}
};
int main() {
C c;
c.somePublicFunction();
B b;
//b.someProtectedFunction(A::Passkey{}); // error: `class A::Passkey` is protected
}
如果是这样,这在什么情况下可能有用?
或者(我想是这样的),为什么它绝对没用? (还有什么其他方法本质上涵盖了这种友谊所提供的能力,而且是以一种更安全、更少泄漏的方式?)
当时我几乎认为我需要这样的东西。我最终采用了完全不同的设计,使所有 class 成员都静态化。不过我还是很好奇。
Is there a way to make all derived classes friends of one another?
该语言不提供任何机制来在基 class 中指定类似的东西。您必须在从基础 class.
继承的每个 class 中提供友元声明我无法提出任何更积极的建议,因为我不知道您要解决的问题。
在评论中,您说:
In my case, I needed to access sibling methods, so if
B
andC
derive fromA
, I needed to callB::foo()
fromC::foo()
. In my case these classes encapsulate different algorithms (so the Strategy pattern comes to mind...) but sometimes one algorithm would use a substantial portion of another algorithm. Yet, it didn't seem correct to deriveC
fromB
, becauseC
doesn't really have an "is-a" relationship withB
.
如果 C
与 B
没有 "is-a" 关系,但 C::foo()
以某种方式需要调用 B::foo()
,这表明我B::foo()
只能使用 B
和 C
共有的数据。在那种情况下,应该可以将代码分解为非成员函数,然后从 B::foo()
和 C::foo()
.
更改依赖于:
B::foo()
^
|
C::foo()
至
<some namespace>::foo()
^
|
+-------+---------+
| |
B::foo() C::foo()
C++ 只给了你两种命名朋友的方法:
friend class C; // a specific class
template <typename T>
friend class S; // friend the class template S
无法在其中插入元函数,假设看起来像这样:
template <typename T>
friend enable_if_t<std::is_base_of<Base, T>::value, T>;
但我想如果你对可怕的黑客行为持开放态度(这句话应该被解释为永远不要这样做,请上帝不,但这至少有点有趣),你可以简单地将所有派生类型实现为显式一些模板的专业化。
struct Base { ... };
template <typename > class Derived;
struct A_tag { };
template <>
class Derived<A_tag> : Base {
template <typename T>
friend class Derived;
...
};
using A = Derived<A_tag>;
如果我们对B
、C
等做类似的事情,那么A
、B
和C
都是朋友-因为在引擎盖下它们实际上是 Derived<A_tag>
、Derived<B_tag>
和 Derived<C_tag>
,因此 friend class 模板语句涵盖了所有这些。
不完全是 friend
,但您可以使用 Passkey pattern
如果您在您的基地 class 中创建受保护的内部密钥 class。然后,任何派生的 classes 都可以通过要求将密钥作为参数来限制对兄弟姐妹的访问:
class A {
protected:
class Passkey {};
};
class B : public A {
public:
void someProtectedFunction(Passkey) {};
};
class C : public A {
public:
void somePublicFunction() {
B b;
b.someProtectedFunction(A::Passkey{});
}
};
int main() {
C c;
c.somePublicFunction();
B b;
//b.someProtectedFunction(A::Passkey{}); // error: `class A::Passkey` is protected
}