【问题标题】:How to restrict access to a non-const public member m of a class A to be const to a another class B, containing A as a non-const member?如何限制对类 A 的非常量公共成员 m 的访问是 const 到另一个类 B,包含 A 作为非常量成员?
【发布时间】:2021-03-01 01:23:48
【问题描述】:

我觉得这个问题对其他人来说也很有趣。所以我选择了这个来最后问我关于 Stack Overflow 的第一个问题。对这种情况的简要描述如下:

class A {
public:
    Type_m_first m_first;
    Type_m_second m_second;
}

class B { // shoud be const on a.m_first
private:
    A& a; 
public:
    B(A& a_) : a(a_) {};
}

编辑: A 的成员设置为private 并使用getter 和setter 并不能解决我的问题。但是,我希望有一个像这样简单的解决方案,因为我可能会因为缺乏编程经验而错过一些简单的东西。

现在,我需要 B 的任何尚未实现的方法,以便只有 const 可以访问 A.m_first 而非const 可以访问 A.m_second,同样,我需要任何在访问B.a 时,使用具有相同访问限制的B 类型的其他代码。当然,这是不可能的(至少从我谦虚的角度来看)。

不过,我的问题是:

如何对B 类强制执行这样的const-限制对非const 成员变量的访问?

编辑 使用私人m_firstm_second 以及m_firstm_second 的getter 和setter,情况将是相同的。那么问题来了:如何限制B访问m_firstconstgetter,拒绝B访问m_first的setter,同时允许B访问使用m_second的setter?


以上是问题。但是,如果没有以下上下文,这个问题可能是不完整的,因为它说明了问题的重要性。我面临的实际情况如下:

class A {
public:
    Type_m_first m_first;
    Type_m_second m_second;
public:
    // A lot of code.
private:
    // A lot of code.
}

class B { // shoud be const on a.m_first
private:
    A& a;
public:
    B(A& a_) : a(a_) {};
private: 
    // A lot of code, that I am supposed to move from somewhere else to here
    // or write myself.
public: 
    // A lot of code, that I am supposed to move from somewhere else to here
    // or write myself.
}

class C { // shoud be const on a.m_second
private:
    A& a;
public:
    C(A& a_) : a(a_) {};
private: 
    // A lot of code, that I am supposed to move from somewhere else to here
    // or write myself.
public: 
    // A lot of code, that I am supposed to move from somewhere else to here
    // or write myself.
}

/* 
 * A lot of other Code that is supposed to work with A, B and C. The following three
 * functions serve as an example. As you see, everything is manipulating essentially 
 * the same data from a.
 */ 

 void f(A& a, /* other args */ ) { /* ... */ }; 
 void g(B& b, /* other args */ ) { /* ... */ }; // shoud be const on b.a.m_first by design
 int h(C& c, /* other args */ ) { /* ... */ };  // shoud be const on c.a.m_second by design
 
 int main() {
     A a; 
     B b = B(a);
     C c = C(a);

     f(a, /* other args */ );
     g(b, /* other args */ );
     return h(c, /* other args */ );
 }
  

同样,我需要 B 的任何尚未实现的方法,只有 const 可以访问 A.m_first,而非 const 可以访问 A.m_second。但是,对于C 类,我需要正好相反:我需要C 的任何尚未实现的方法,只有const 可以访问A.m_second,而没有@ 987654355@ 访问A.m_first。同样,任何使用 BC 类型的代码都应该有相应的访问限制。

当然,问题又来了:我为什么需要这个?答案是,算法的逻辑结构将由这样的设计强制执行。到目前为止,公开所有内容只是一个问题,因为意外忽略逻辑结构会导致难以发现代码中的错误,并且由于代码的复杂性,很难跟踪这些设计未强制执行的限制.

我想出的最佳解决方案 - 但尚未实现 - 是将代码复制到两个包装类:

class A_first {
public:
    const Type_m_first& m_first;
    Type_m_second& m_second;
    A_first(A&) ; m_first(const A.m_first), m_second(A.m_second) {};
public:
    // Same code as before.
protected:
    // Same code as before.
private:
    // Same code as before.
}

class A_second {
public:
    Type_m_first& m_first;
    const Type_m_second& m_second;
    A_first(A&) ; m_first(A.m_first), m_second(const A.m_second) {};
public:
    // Same code as before.
protected:
    // Same code as before.
private:
    // Same code as before.
}

这并不可取,因为随着时间的推移代码会发生很大变化,并且跟踪三个类的变化很容易出错。我的问题是,遇到这种情况该怎么办?

【问题讨论】:

  • 如果不了解我们看不到的代码,很难给出建议。但是@HAL9000 的答案已经指出了方向:如果一个数据成员不被在一个类之外(即默认值)操作,它应该是私有的并且应该有 getter / setter 方法。此外,操作 A 的数据成员的代码最好也位于 A 内部; B 和 C 也是如此。所以也许你的函数 f、g、h 可能最终成为 A、B 和 C 的方法。
  • @kaba 非常感谢,我编辑了问题并使其更加清晰。

标签: c++ software-design const-correctness


【解决方案1】:

我非常怀疑这是否值得努力,但这可能适合您的需求:

不要将BC 传递给A 的引用(这将授予他们对A 的无限制访问权限,如果我理解正确的话,这是你的全部问题),只将访问器传递给这两个成员。这可能看起来像这样:

class B {
private:
    std::function<Type_m_first const&()> getConstFirst;
    std::function<Type_m_second&()> getNonConstSecond;
public:
    B(std::function<Type_m_first const&()> f1, std::function<Type_m_second&()> f2)
        : getConstFirst(std::move(f1)), getNonConstSecond(std::move(f2)) {};

    void someMethod() {
        getConstFirst() = abc; // this won't compile
        getNonConstSecond() = xyz; // this will
    }
}

C 的类似实现。

然后,使用通过引用捕获 A 实例的 lambdas 将函数传递给 BC 的 c'tors:

A a; 
B b = B(
    [&a]() -> auto const& { return a.m_first; },
    [&a]() -> auto& { return a.m_second; }
    );
C c = C(
    [&a]() -> auto& { return a.m_first; },
    [&a]() -> auto const& { return a.m_second; }
    );

【讨论】:

  • 非常感谢。这是我的问题的答案。这比我希望的要复杂,因此我还没有接受它作为答案。如果我自己找不到不同的解决方案,或者在一段时间内找不到更好的答案,我会接受这个答案。
  • (我不确定这是否符合 stackoverflow 上的网络礼仪。如果不是,我很乐意做不同的事情。如果有人好心向我指出这一点。)
  • 后续问题:为什么需要std::move()?
  • @Kokoro 不接受它以等待更好的东西是完全可以的 :) std::move 是没有必要的。它只是避免复制。如果你不喜欢它,你可以忽略它。
【解决方案2】:

好吧,我不得不承认,我只是略读了你的问题,所以我可能错过了一些细节。但是,返回 const 引用的 getter 不是您需要的吗?

class A {
private:
    Type_m_first m_first;
public:
    const Type_m_first & get_m_first() const { return m_first; }

    Type_m_second m_second;
}

这里只有A 的成员可以直接修改m_first。其他人必须使用get_m_first 获得的const 引用。

【讨论】:

  • 非常感谢,我编辑了问题并使其更加清晰。
  • @HAL9000 现在 m_first 是私有的,所以你需要一个 setter。你将如何实现它?
  • 如果要求只有 const 访问 m_first 那么你为什么需要一个 setter? const 表示不可修改...
猜你喜欢
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 2010-11-15
  • 2019-05-04
  • 1970-01-01
  • 2013-03-25
  • 2014-11-01
  • 1970-01-01
相关资源
最近更新 更多