干净的 C++ 粒度朋友等价物?(答案:律师-客户成语)

2021-12-22 00:00:00 private design-patterns c++ friend

为什么 C++ 有任何人都可以调用的 public 成员和公开 all private 成员的 friend 声明给定外部类或方法,但没有提供将特定成员暴露给给定调用者的语法?

Why does C++ have public members that anyone can call and friend declarations that expose all private members to given foreign classes or methods but offer no syntax to expose particular members to given callers?

我想用一些例程来表达接口,这些例程只能由已知调用者调用,而不必让这些调用者完全访问所有私有信息,这感觉是合理的.到目前为止,我能想到的最好的我自己(如下)和其他人的建议都围绕着不同间接性的习语/模式,我真的只是想要一种单一的方法,简单的类定义明确表明哪些呼叫者(比我、我的孩子或绝对是任何人更精细)可以访问哪些成员.表达以下概念的最佳方式是什么?

I want to express interfaces with some routines to be invoked only by known callers without having to give those callers complete access to all privates, which feels like a reasonable thing to want. The best I could come up with myself (below) and suggestions by others so far revolve around idioms/pattern of varying indirectness, where I really just want a way to have single, simple class definitions that explicitly indicate what callers (more granularly than me, my children, or absolutely anybody) can access which members. What is the best way to express the concept below?

// Can I grant Y::usesX(...) selective X::restricted(...) access more cleanly?
void Y::usesX(int n, X *x, int m) {
  X::AttorneyY::restricted(*x, n);
}

struct X {
  class AttorneyY;          // Proxies restricted state to part or all of Y.
private:
  void restricted(int);     // Something preferably selectively available.
  friend class AttorneyY;   // Give trusted member class private access.
  int personal_;            // Truly private state ...
};

// Single abstract permission.  Can add more friends or forwards.
class X::AttorneyY {
  friend void Y::usesX(int, X *, int);
  inline static void restricted(X &x, int n) { x.restricted(n); }
};

我离成为一名软件组织大师还差得很远,但感觉界面简单性和最小权限原则在语言的这方面直接矛盾.我想要的一个更清晰的例子可能是一个 Person 类,其中声明了诸如 takePill(Medicine *) tellTheTruth()forfeitDollars(unsigned int) 只有 PhysicianJudgeTaxMan 实例/成员方法,分别应该考虑调用.每个主要接口方面都需要一次性代理或接口类让我感到不适,但如果您知道我遗漏了什么,请说出来.

I'm nowhere near being a software organization guru, but it feels like interface simplicity and the principle of least privilege are directly at odds in this aspect of the language. A clearer example for my desire might be a Person class with declared methods like takePill(Medicine *) tellTheTruth() and forfeitDollars(unsigned int) that only Physician, Judge, or TaxMan instances/member methods, respectively, should even consider invoking. Needing one-time proxy or interface classes for each major interface aspect sits ill with me, but please speak up if you know I'm missing something.

从 Drew Hall 接受的答案:多布斯博士 - 友谊和律师-客户成语

Answer accepted from Drew Hall: Dr Dobbs - Friendship and the Attorney-Client Idiom

上面的代码最初将包装类称为Proxy"而不是Attorney",并使用指针而不是引用,但在其他方面与 Drew 发现的等效,然后我认为这是最广为人知的解决方案.(不要太用力拍自己的背……)我还更改了'restricted'的签名以演示参数转发.这个习惯用法的总成本是每个权限集一个类和一个友元声明,每个许可调用者集一个友元声明,每个权限集每个公开的方法一个转发包装器.下面大部分更好的讨论都围绕着转发调用样板,一个非常相似的关键"习语以较少的直接保护为代价避免了该样板.

The code above originally called the wrapper class 'Proxy' instead of 'Attorney' and used pointers instead of references but was otherwise equivalent to what Drew found, which I then deemed the best generally known solution. (Not to pat myself on the back too hard...) I also changed the signature of 'restricted' to demonstrate parameter forwarding. The overall cost of this idiom is one class and one friend declaration per permission set, one friend declaration per set approved caller, and one forwarding wrapper per exposed method per permission set. Most of the better discussion below revolves around the forwarding call boilerplate that a very similar 'Key' idiom avoids at the expense of less direct protection.

推荐答案

Attorney-Client idiom可能就是你要找的.机制与您的成员代理类解决方案没有太大区别,但这种方式更惯用.

The Attorney-Client idiom may be what you're looking for. The mechanics are not too different from your member proxy class solution, but this way is more idiomatic.

相关文章