C++ 如何将对类a的非常量公共成员m的访问限制为对另一个类B的常量访问,该类B包含作为非常量成员的a?

C++ 如何将对类a的非常量公共成员m的访问限制为对另一个类B的常量访问,该类B包含作为非常量成员的a?,c++,software-design,const-correctness,C++,Software Design,Const Correctness,晚上好 我发现这个问题对其他人来说也很有趣。所以我选择这一个来最后问我关于堆栈溢出的第一个问题。以下是对情况的简要描述: 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_) {}; } class A {

晚上好

我发现这个问题对其他人来说也很有趣。所以我选择这一个来最后问我关于堆栈溢出的第一个问题。以下是对情况的简要描述:

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_) {};
}
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 */ );
 }
  
编辑:
A
的成员设置为
private
并使用getter和setter并不能解决我的问题。然而,我希望有这样一个简单的解决方案,因为我可能会错过一些简单的东西,因为我缺乏编程经验

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

不过,我的问题是:

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

编辑使用private
m_first
m_second
以及
m_first
m_second
的getter和setter,情况将是相同的。然后问题是:如何限制
B
m_first
const
获取者的访问,并拒绝
B
m_first
的设置者的访问,同时允许
B
使用
m_second
的设置者


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

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_) {};
}
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\u-first
,而非
const
访问
A.m\u-second
。然而,对于类
C
而言,我需要的恰恰相反:我需要任何尚未实现的
C
方法,只有
const
访问
A.m_second
,而非
const
访问
A.m_second
。类似地,任何使用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.
}

这是不可取的,因为代码随时间变化很大,并且跟踪三个类中的变化很容易出错。我的问题是,在这种情况下该怎么办?

好的,我不得不承认,我只是略读了一下你们的问题,所以我可能错过了一些细节。但是,返回
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\u
。其他所有人都必须使用
const
引用,该引用由
get\m\u first

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

与其传递
B
C
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
    }
}

如果不了解我们看不到的代码,就很难给出建议。但是@HAL9000的答案已经指出了方向:如果一个数据成员不在类之外操作(即默认值),那么它应该是私有的,并且应该有getter/setter方法。此外,操作例如A的数据成员的代码最好也应该位于A内部;B和C也是一样。因此,也许你的函数f、g、h最终可能是A、B和C的方法。@kaba非常感谢,我编辑了这个问题,使它更清楚。非常感谢,我编辑了这个问题,使它更清楚。@HAL9000既然m_第一个是私有的,那么你需要一个setter。您将如何实现它?如果要求首先只能对
m_
进行const访问,那么您为什么需要setter?Const的意思是不可修改的…非常感谢。这是对我问题的回答。这比我希望的要复杂得多,因此我还没有接受它作为一个答案。如果我自己找不到不同的解决方案,或者在一段时间内找不到更好的答案,我会接受这个答案。(我不确定这是否符合stackoverflow上的netiquette。如果不是,我很乐意做不同的事情。如果有人足够好地向我指出这一点。)跟进问题:为什么std::move()必要吗?@Kokoro为了等待更好的东西而不接受它是完全可以的:)
std::move
是不必要的。它只是避免复制。如果你不喜欢,你可以把它删掉。