如何允许某些 classes 的对象访问另一个 classes 的对象的受保护成员

How to allow objects of some classes to access protected members of an object of another class

我正在寻找以下问题的解决方案:

我有一个 class X,(假设)只有 protected 个成员。我有一组 S 几个 classes A, B, C, ...

假设存在 class X 成员的现有实例 x(该实例可能是 class X 的实例,或者任何合适的实例的子集 container/derived-class/... 取决于 class X) :

此外,在给定时间,只有一个实例 s [x 相关 ] 存在。

换句话说,为了阐明上述要求:我需要任何实例 s 都可以访问 class Xprotected 成员,就像如果 (例如) S 的 classes 是从 X 公开派生的,除了来自 class [=13= 的成员子集] in inheritance 必须保持 alive 并且 unaltered 无论实例 s 是创建还是销毁。

此外,必须满足以下要求:

当前实施的解决方案虽然不满足要求 #5,但正在为 S 朋友的 class 部分使用组合和父 class X 个,例如:

class X
{
    // public: int get_prot();        // not allowed (rq#2)
    protected: int prot;
    friend class Xaxx;
    // friend A; friend B; ...        // not acceptable (rq#6)
};

class Xacc
{
protected:
    Xacc(X& x) : x(x) {}
    int& x_prot() { return x.prot; }  // not desirable (rq#5)
    X& x;
};

class A : public Xacc
{
public:
    A(X& x) : Xacc(x) {}
    void work()  { x_prot() = 1; }
};

测试了另一个有趣的解决方案,它满足除 #4 以外的所有要求:

class A : public X
{
public:
    A(const X& x) : X(x) {}            // X not copyable (rq#4)
    void work()  { prot = 1; }
};

任何高达 C++14 的解决方案都是可以接受的。感谢您的帮助。


理由:

澄清这个问题的根源以及解决方案将以何种方式帮助我改进我的代码:

让外部 class 成为需要访问的 class 的朋友是不可能的吗?

http://www.cplusplus.com/doc/tutorial/inheritance/

我认为解决方案是:你的集合 S 必须有一个基础 class。

S 可以是您的 class X 或来自 X

的分离(新)class

软件项目是需求和设计的平衡,当您列出所有 6 个需求时,解决方案仅限于您必须有一个具有共同功能的基础 class Xacc:访问您的 X

你知道故事"castles in the air"吗?我怎么只有2楼没有1楼?

或许您可以使用 passkey 模式的一些变体

class XKey {
    XKey(){}
    friend class Xacc;
};

class X {
public: 
    int& get_prot(XKey) { return prot; } // Only accessible to those who can construct XKey
protected:
    int prot;
};

class Xacc {
protected:
    Xacc(X& x) : x(x) {}
    X& x;    
    XKey getKey() { return XKey(); }    
};

class A : public Xacc {
public:
    A(X& x) : Xacc(x) {}
    void work()  { x.get_prot(getKey()) = 1; }
};

int main() {
    X x;
    A a(x);
    a.work();
    //x.get_prot(XKey()) = 2;  // Error: XKey::XKey() is private   
}

如果您在 S 中的 classes 具有简单的统一接口(例如单个 'work' 方法),您可以更改当前的实现通过使 Xacc 成为模板 class 并将对 X 的受保护部分的访问的实现移动到 Xacc 的特化中来满足要求 #5。它看起来像这样:

class X 
{
protected:
    int prot;
    template<typename State> friend class Xacc;
};

template<class State>
class Xacc
{
public:
    Xacc(X &x) : x(x) {}
    void work();
private:
    X &x;
};

class S1;
template<> void Xacc<S1>::work()
{
    x.prot = 1;
};

class S1: public Xacc<S1>
{
public:
    S1(X &x): Xacc<S1>(x) {}
protected:
};