当对象被其他对象引用时,有关const限定符的一个微妙问题

时间:2019-06-03 13:45:53

标签: c++ const

想象一下,我有一个对象A,该对象A通过其地址引用了对象B。 B的地址在A的构造函数中给出。 A的某些方法可以修改B,其他方法则不能。

这是一个非常简单的例子:

class B {
public :
void f1() const;
void f2();
};

class A {
public :
 A(B * pb) {m_pb=pb;}
 void g1() {m_pb->f1();} // g1 do not modify *m_pb
 void g2() {m_pb->f2();} // g2 do modify *m_pb
private :
  B * m_pb;
}

现在,假设在我的代码的某些部分中,我有一个类型为const B&的变量。我想创建一个对象A来调用不修改对象B的g1方法。但是我根本无法构造对象A。

一种解决方案是创建两个类A1和A2,其中A1引用const B *并仅定义方法g1,而A2引用B *并定义g1和g2。 (g1将在2个不同的位置定义)。我觉得这种解决方案不是很优雅。

我想知道是否有一种方法可以向编译器解释: const A不会修改它所引用的对象B。因此可以使用const B对象构造const A对象。

1 个答案:

答案 0 :(得分:2)

  

我想知道是否有一种方法可以向编译器解释:const A不会修改它所引用的对象B.因此可以使用const B对象构造const A对象。

您想要的是const constructor,没有一个。但是您可以避免使用继承来复制接口:

struct B{
    void f1() const{}
    void f2() {}
};

class constA
{
public:
    constA(const B* b):b(b){}
    // Should be const as it does not changes `constA` object.
    void g1() const {b->f1();}

    // No harm in this, but can be protected if you want
    const B* getB() const { return b;}
private:
    const B* b;
};

class A : public constA
{
public:
    A(B* b):constA(b){}
    void g2() const { getMutableB()->f2();}
private:
    B* getMutableB() const { return const_cast<B*>(getB());}
};

int main()
{
   B b;
   const B cb;

   A a(&b);
   a.g2();
   a.g1();

   constA ca(&cb);
   ca.g1();
   //ca.g2();

   constA ca2(&b);
   ca.g1();
   //ca.g2();

}

编辑:(根据我同意的@ formerlyknownas_463035818的请求)在const_cast上进行快速刷新:

int main()
{
    const int x = 5;
    int y = 5;
    const int* c_ptr = &x; 
    //'ptr' is valid object with known value.
    int* ptr = const_cast<int*>(c_ptr);
    // Is valid because '*ptr' is not modified
    int value = *ptr;
    // Undefined behaviour because '*ptr' is const object.
    *ptr = 5;

    const int* c_ptr2 = &y; 
    //'ptr2' is valid object with known value.
    int* ptr2 = const_cast<int*>(c_ptr2);
    // Is valid because '*ptr2' is not modified
    int value = *ptr2;
    // Is valid because '*ptr2' is not a const object.
    *ptr2 = 5;
}

鉴于A仅具有非常量B构造函数,则getB()始终返回指向非const对象的指针。因此,上面示例的第二部分适用,一切都安全。

请注意,在调用const B时,将const cast A传递给g2会产生UB,但这对于所有来历不明的B* ptr都是如此, A类对此无能为力。