从const方法访问成员指针的非const方法时的最佳实践

Best practice when accessing a non-const method of a member pointer from a const-method

本文关键字:方法 const 最佳 指针 访问 成员      更新时间:2023-10-16

考虑以下情况

class A
{
public:
    void someFunc() const
    {
         b->nonConstFunction(); //this is a non const function in the class B
    }
private:
    B* b;
};

在常数函数someFunc()中,我可以调用b的任何非常数方法,并将其编译。所以函数someFunc()不是一个真正的const函数。但是所有的最佳实践都表明,应该把const放在任何可能的地方。这个建议是否也适用于这里?可能将函数void someFunc()声明为非常数比将void someFunc() const声明为非常数更诚实。或者也许有一个更普遍的建议来处理这类事情?

不是一个真正的const函数

嗯,这取决于你想表达什么。

  1. 如果A的状态在逻辑上取决于b的状态(这是我从你的问题中得到的暗示)

    • 最简单的解决方案是给A一个B类型的成员,而不是使用指针或引用。然后在你的const方法中有一个const B,它直接表达了你的需求

    • 下一个最简单的方法是首先将成员声明为const B *b; -显然,如果你还需要A的非const方法来调用b的非const方法,这是行不通的。

    • 如果您需要间接,另一种可能性是使用智能指针类(我不确定是否已经存在合适的类)与操作符重载,如

       B* operator->();
       const B* operator->() const;
      

      可以保证你想要的

  2. 如果A的状态逻辑依赖于b

    在这种情况下,您没有问题:在const方法中改变b是可以的,因为A的逻辑状态没有改变。当你有一个指向eg的指针时,可能经常会出现这种情况。

如果A不"拥有" b,则为const。现代c++表示,通过使b为unique_ptr, A是所有者,如果只是链接,则为普通指针。

似乎C++认为B不是A的一部分,但A连接到 B。由于B不是const,因此A可以调用其非const方法。但是因为Aconst,你不能让A指向不同的B。如果你把B设置为成员,那么你就不能再调用它的非const方法,因为它现在是A的一部分。

我认为使用std::unique_ptr会解决这个问题,但显然std::unique_ptr从其const箭头操作符->返回一个非const指针。

可以通过创建一个指针包装器来解决这个问题,该包装器将constness传递给所包含的指针,如下所示:

template<typename T>
class const_correct_ptr
{
public:
    const_correct_ptr(std::unique_ptr<T>): p(std::move(p)) {}
    // pass constness onto target
    T* operator->() { return p.get(); }
    T const* operator->() const { return p.get(); }
private:
    std::unique_ptr<T> p;
};
class B
{
public:
    void nonConstFunction() {}
};
class A
{
public:
    A(): b(std::make_unique<B>()) {}
    void someFunc() const
    {
         b->nonConstFunction(); // compile time error!
    }
private:
    const_correct_ptr<B> b;
};