When should I make explicit use of the `this` pointer?

后端 未结 12 1284
甜味超标
甜味超标 2020-11-22 15:19

When should I explicitly write this->member in a method of a class?

相关标签:
12条回答
  • 2020-11-22 15:53

    The main (or I can say, the only) purpose of this pointer is that it points to the object used to invoke a member function.

    Base on this purpose, we can have some cases that only using this pointer can solve the problem.

    For example, we have to return the invoking object in a member function with argument is an same class object:

    class human {
    
    ... 
    
    human & human::compare(human & h){
        if (condition)
            return h;       // argument object
        else 
            return *this;   // invoking object
        }
    };
    
    0 讨论(0)
  • 2020-11-22 15:55

    Although I usually don't particular like it, I've seen others use this-> simply to get help from intellisense!

    0 讨论(0)
  • 2020-11-22 15:56

    If you declare a local variable in a method with the same name as an existing member, you will have to use this->var to access the class member instead of the local variable.

    #include <iostream>
    using namespace std;
    class A
    {
        public:
            int a;
    
            void f() {
                a = 4;
                int a = 5;
                cout << a << endl;
                cout << this->a << endl;
            }
    };
    
    int main()
    {
        A a;
        a.f();
    }
    

    prints:

    5
    4

    0 讨论(0)
  • 2020-11-22 16:00

    Usually, you do not have to, this-> is implied.

    Sometimes, there is a name ambiguity, where it can be used to disambiguate class members and local variables. However, here is a completely different case where this-> is explicitly required.

    Consider the following code:

    template<class T>
    struct A {
       int i;
    };
    
    template<class T>
    struct B : A<T> {
    
        int foo() {
            return this->i;
        }
    
    };
    
    int main() {
        B<int> b;
        b.foo();
    }
    

    If you omit this->, the compiler does not know how to treat i, since it may or may not exist in all instantiations of A. In order to tell it that i is indeed a member of A<T>, for any T, the this-> prefix is required.

    Note: it is possible to still omit this-> prefix by using:

    template<class T>
    struct B : A<T> {
    
        using A<T>::i; // explicitly refer to a variable in the base class
    
        int foo() {
            return i; // i is now known to exist
        }
    
    };
    
    0 讨论(0)
  • 2020-11-22 16:00

    The other uses for this (as I thought when I read the summary and half the question... .), disregarding (bad) naming disambiguation in other answers, are if you want to cast the current object, bind it in a function object or use it with a pointer-to-member.

    Casts

    void Foo::bar() {
        misc_nonconst_stuff();
        const Foo* const_this = this;
        const_this->bar(); // calls const version
    
        dynamic_cast<Bar*>(this)->bar(); // calls specific virtual function in case of multi-inheritance
    } 
    
    void Foo::bar() const {}
    

    Binding

    void Foo::baz() {
         for_each(m_stuff.begin(), m_stuff.end(),  bind(&Foo:framboozle, this, _1));        
         for_each(m_stuff.begin(), m_stuff.end(), [this](StuffUnit& s) { framboozle(s); });         
    } 
    
    void Foo::framboozle(StuffUnit& su) {}
    
    std::vector<StuffUnit> m_stuff;
    

    ptr-to-member

    void Foo::boz() {
        bez(&Foo::bar);
        bez(&Foo::baz);
    } 
    
    void Foo::bez(void (Foo::*func_ptr)()) {
        for (int i=0; i<3; ++i) {
            (this->*func_ptr)();
        }
    }
    

    Hope it helps to show other uses of this than just this->member.

    0 讨论(0)
  • 2020-11-22 16:02

    There are few cases where using this must be used, and there are others where using the this pointer is one way to solve a problem.

    1) Alternatives Available: To resolve ambiguity between local variables and class members, as illustrated by @ASk.

    2) No Alternative: To return a pointer or reference to this from a member function. This is frequently done (and should be done) when overloading operator+, operator-, operator=, etc:

    class Foo
    {
      Foo& operator=(const Foo& rhs)
      {
        return * this;
      }
    };
    

    Doing this permits an idiom known as "method chaining", where you perform several operations on an object in one line of code. Such as:

    Student st;
    st.SetAge (21).SetGender (male).SetClass ("C++ 101");
    

    Some consider this consise, others consider it an abomination. Count me in the latter group.

    3) No Alternative: To resolve names in dependant types. This comes up when using templates, as in this example:

    #include <iostream>
    
    
    template <typename Val>
    class ValHolder
    {
    private:
      Val mVal;
    public:
      ValHolder (const Val& val)
      :
        mVal (val)
      {
      }
      Val& GetVal() { return mVal; }
    };
    
    template <typename Val>
    class ValProcessor
    :
      public ValHolder <Val>
    {
    public:
      ValProcessor (const Val& val)
      :
        ValHolder <Val> (val)
      {
      }
    
      Val ComputeValue()
      {
    //    int ret = 2 * GetVal();  // ERROR:  No member 'GetVal'
        int ret = 4 * this->GetVal();  // OK -- this tells compiler to examine dependant type (ValHolder)
        return ret;
      }
    };
    
    int main()
    {
      ValProcessor <int> proc (42);
      const int val = proc.ComputeValue();
      std::cout << val << "\n";
    }
    

    4) Alternatives Available: As a part of coding style, to document which variables are member variables as opposed to local variables. I prefer a different naming scheme where member varibales can never have the same name as locals. Currently I'm using mName for members and name for locals.

    0 讨论(0)
提交回复
热议问题