【问题标题】:How is the 'this' pointer used as an argument of a member function'this' 指针如何用作成员函数的参数
【发布时间】:2013-04-17 04:21:59
【问题描述】:

我有这个简单的课程

class foo {
public:
  void func() const;
  void func2();
};

void foo::func() const {}
void foo::func2() {}

int main() {
  const foo f;
  f.func();
  f.func2();
}

当我尝试编译时,我收到以下消息:

错误:将“const foo”作为“void foo::func2()”的“this”参数传递会丢弃限定符 [-fpermissive]

我了解 const 对象的非 const 成员的使用,我的问题是 'this' 指针用作 func2 的参数?

【问题讨论】:

  • const foo f; 更改为foo f,“f.func2()”应该可以正常编译。否则,将 func2() 更改为“const”也应该可以解决问题。无论哪种方式,任何时候调用对象的方法时,都会传递一个“this”指针。由于您声明了 object f "const",并且由于 func2() 是非 const ...编译器在抱怨。

标签: c++


【解决方案1】:

void foo::func2() 是非常量的,这意味着它可能会改变对象。因此,编译器不允许您为 const 对象调用它。即使您实际上并没有更改func2 的实现中的任何内容。 this 是任何非静态成员函数的隐式参数。这就是它知道它被调用的确切对象的方式。

9.3.2 this 指针[class.this]

1 在非静态 (9.3) 成员函数的主体中,关键字 this 是纯右值表达式,其值 是调用函数的对象的地址。

【讨论】:

  • 是的,我知道了。我感兴趣的是编译器消息将“this”指针作为 func2 的参数。我试图弄清楚这意味着什么。 'this' 是成员函数的隐式参数吗?
  • @RichardJohnson this 是任何非静态成员函数的隐式参数。这就是它知道它被调用的确切对象的方式
【解决方案2】:

您看到的是 C++ 定义方式的产物。成员函数会自动为每个函数添加一个隐藏的this 参数。如果对象是const,那么指针也是const,并且非常量成员函数必须接收非常量this指针。

【讨论】:

  • 为了记录而做的小说明 - 非static 成员函数得到隐藏的this - static 成员函数没有。
【解决方案3】:

成员函数的实例参数是隐式。也就是说,它从来不是函数声明的一部分,但它仍然存在。

请记住,(非静态)成员函数不是函数。你不能只是调用他们。相反,您必须始终在 instance 对象上调用它们。这个实例对象隐含地是成员函数的一个参数,但从未拼写出来。它可以通过this 表达式在函数内部使用。

如果隐式实例参数绑定到一个常量对象,那么this的类型是T const *,并且只能调用限定为const的成员函数。 volatile 类似,也有类似的规则将隐式实例参数绑定到右值引用。

【讨论】:

    【解决方案4】:

    您不能在 const 对象 f 上调用非 const 函数 func2

    因为你的问题是:

    this 指针如何用作 func2 的参数

    这里引用了IBM C++ documentation: this pointer的一些信息:

    关键字this 标识一种特殊类型的指针。假设 您创建了一个名为 x 的对象,该对象属于 A 类,而 A 类有一个 非静态成员函数f()。如果调用函数x.f(),则 f()正文中的关键字this存储x的地址。你 无法声明 this 指针或对其进行赋值。

    static 成员函数没有 this 指针。

    类类型成员函数的this指针类型 X,是X* const。如果使用 const 限定符声明成员函数,则该成员的this 指针的类型 X 类的函数是 const X* const

    const this 指针只能与const member functions 一起使用。 类的数据成员将在该函数中保持不变。这 函数仍然能够改变值,但需要一个 const_cast 这样做:

    void foo::p() const{    
        member = 1;                       // illegal    
        const_cast <int&> (member) = 1;   // a bad practice but legal 
    } 
    

    更好的技术是声明成员可变

    .

    【讨论】:

      【解决方案5】:

      在 OOP 中(通常),所有实例方法都由编译器静默转换为静态函数,并添加指向包含实例状态的结构的指针(即this)作为隐藏的第一个参数。

      所以这个:

      class Foo
      {
          private:
              Int32 _bar;
      
          public:
              void Add(Int32 x)
              {
                  this->_bar += x;
              }
      };
      
      void Main()
      {
          Foo foo;
          foo.Add(3);
      }
      

      实际上是这样实现的:

      struct Foo {
          Int32 _bar;
      }
      
      static void Foo_Add(Foo *thisPtr, Int32 x)
      {
          thisPtr->_bar += x;
      }
      
      void Main()
      {
          Foo foo;
          Foo_Add( &foo, 3 );
      }
      

      【讨论】:

      • 所以错误实际上只是一个简单的类型不匹配,因为它不允许将 const 对象隐式转换为非 const 对象。
      【解决方案6】:

      你的成员函数 func2() 应该是 const。见here

      【讨论】:

        【解决方案7】:

        在计算机上运行的实际代码中,func2 的代码需要知道要查看/执行操作的 foo 的哪个实例。所以它被传递了一个指向实例的指针(this)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-09
          • 2013-06-29
          • 2014-10-18
          相关资源
          最近更新 更多