【问题标题】:Understand const correctess with pointers in C++用 C++ 中的指针理解 const 的正确性
【发布时间】:2021-10-18 14:45:42
【问题描述】:

我有以下测试代码:

class A
{
    public:
    void funcA()
    {
        std::cout << "banana" << std::endl;
    }
};

class B
: public A
{
    public:
    A t;

    void funcB() const
    {
       t.funcA();
    }
};

int main(int argCount, char *args[])
{
   B tst;
   tst.funcB();
}

其中funcA 没有const定义,而funcBconst 定义。

编译代码时出现错误:

passing ‘const A’ as ‘this’ argument discards qualifiers [-fpermissive]

这应该发生,因为我在 const 函数内部调用了 non-const 函数。

但是,当我这样做时:

class B
: public A
{
    public:
    A* t;

    void funcB() const
    {
       t->funcA();
    }
};

代码编译并工作。这是为什么?我只是用g++ -g main.cpp 编译,我缺少这个标志?还是这种行为是意料之中的?

【问题讨论】:

  • 你想要const A *t 而不是A *t。请记住,您正在修改 t 指向的对象,而不是 t 本身,因此编译器认为这很好。
  • 为什么你有A 作为B 的基类 作为B 的成员?您根本没有使用基类,因此可以将其从 sn-ps 中删除(以减少混淆)并仅保留成员 t。第一个 sn-p 不会编译,因为t(嵌入在B 实例中的A 的实际实例)是const,就像this 指向的周围的B 实例一样在。在第二个 sn-p 中,t 指向 A 的非 const 实例(即使指针 t 本身是 const),您可以(当然)在其上调用任意非-const 方法。
  • t本身就是const,而不是t指向的对象。
  • std::experimental::propagate_const 可能有预期的行为。

标签: c++ c++11


【解决方案1】:

您不是在修改指针成员变量,而是在修改它指向的值,所以它可以编译。

t 变量是指向A 类型变量的指针。执行t-&gt;funcA(); 可能会改变变量指向的值,但不会改变指针成员本身,这就是编译器需要在这里强制执行的全部内容。

如果你像这样修改实际的指针,这个函数将无法编译。

void funcB() const 
{
    t = nullptr; //Will not compile
}

如果要防止有人通过指针修改A变量,只需将指针声明为const即可。这将防止修改它指向的值。

const A* t;

【讨论】:

    【解决方案2】:

    案例一:解释你的第一个代码 sn-p

    当我们写作时

    void funcA();  
    

    这意味着 funcA() 有一个类型为 A *const 的隐式参数,即指向非 const A 对象的 const 指针。这反过来意味着我们只能在非常量 A 对象上调用这个函数。如果您尝试在 const A 对象上调用此成员函数,您将收到上述错误。

    为了说明我的观点,让我们尝试在 const A 对象上调用 funcA。代码如下:

    #include <iostream>
    
    class A
    {
        public:
        void funcA()
        {
            std::cout << "banana" << std::endl;
        }
    };
    
    int main()
    {
      A nonconstobject;
      nonconstobject.funcA(); //this works
      
      const A constobject;  //note the const here
      constobject.funcA(); //this gives error: passing ‘const A’ as ‘this’ argument discards qualifiers
    }
    

    上面的 sn-p 给出了与您提到的相同的错误,可以看到 here

    这正是您的第一个代码 sn-p 中发生的情况。现在我将逐步解释您的第一个代码 sn-p 中发生的情况:

    第 1 步。您已将 funcB(); 声明为 const 成员函数。这意味着它自己的隐式参数的类型为const B *const,即指向 const B 对象的 const 指针。这又意味着 B 的数据成员(包括数据成员 t)本身就是 const。

    第 2 步。现在因为 tconst 并且正如我在我的自定义示例中所说,您不能在 const 对象上调用非常量成员函数。所以你得到了你提到的错误。

    案例 2:第二个代码 sn-p 的解释

    在第二种情况下,您已将数据成员 t 更改为 A* 类型,即指向 A 对象的指针。

    现在让我们逐步看一下在这种情况下会发生什么:

    第 1 步。您已将 funcB(); 声明为 const 成员函数。这意味着它自己的隐式参数的类型为const B *const,即指向 const B 对象的 const 指针。这反过来意味着 B 的数据成员(包括数据成员 t)本身就是 const。这次的不同之处在于 t 将成为指向 A 的 const 指针,即 t 的类型为 A* const

    第 2 步。同样,funcA 具有 A *const 类型的隐式参数,因为 funcA 不是 const 成员函数。这种类型与您使用调用 t-&gt;funcA(); 传递的内容完全匹配。所以在这种情况下你不会得到任何错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多