Когда я должен сделать конкретный вид использования 'этого' указателя?

У меня была проблема с matchit, находящим правильную подходящую фигурную скобку в C ++ / C, когда были закомментированные фигурные скобки. Следующие шаги, взятые из этого поста на форуме , написанного этим парнем , решили его для меня, а также в значительной степени объяснили, как все это работает:

  1. Создайте папку ~ / .vim / plugin, если ее там еще нет:

    mkdir ~/.vim/plugin 
    
  2. Создайте файл с именем ~ / .vim / plugin / matchit. vim:

    vi ~/.vim/plugin/matchit.vim 
    

    и следующее содержимое:

    runtime macros/matchit.vim 
    
  3. Создайте каталог ~ / .vim / doc, если его там еще нет:

    mkdir ~/.vim/doc
    
  4. Скопируйте /usr/share/vim/vim73/macros/matchit.txt в ~ / .vim / doc /:

    cp /usr/share/vim/vim73/macros/matchit.txt ~/.vim/doc/
    
  5. Откройте vi

    vi
    

    и выполните в нем следующее:

    :helptags ~/.vim/doc 
    
  6. Убедитесь, что ваш ~ / .vimrc включает одно из следующего:

    source $VIMRUNTIME/vimrc_example.vim 
    

    или

    runtime vimrc_example.vim 
    

    или

    filetype plugin on 
    

    или

    filetype plugin indent on 
    
  7. Добавьте в свой vimrc следующую автокоманду :

    " make matchit work on C-like filetypes 
    " c and cpp are already handled by their ftplugin 
    au Filetype css,javascript 
            \ let b:match_words = &matchpairs 
    
  8. Перезапустите Vim.

88
задан dmckee 14 June 2009 в 18:14
поделиться

11 ответов

Обычно этого не требуется, это -> подразумевается.

Иногда возникает двусмысленность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда явно требуется this -> .

Рассмотрим следующий код:

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();
}

Если вы опустите this -> , компилятор не знать, как обрабатывать i , поскольку он может существовать или не существовать во всех экземплярах A . Чтобы сообщить ему, что i действительно является членом A , для любого T префикс this -> является обязательным.

Примечание: можно все еще опустить этот -> префикс, используя:

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
    }

};
111
ответ дан 24 November 2019 в 07:30
поделиться

Если вы объявляете локальную переменную в методе с тем же именем, что и существующий член, вам придется использовать this-> var для доступа к члену класса вместо локальной переменной.

#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();
}

печатает:

5
4

30
ответ дан 24 November 2019 в 07:30
поделиться

Обычно это не требуется, это -> подразумевается.

Иногда возникает двусмысленность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда явно требуется this -> .

Рассмотрим следующий код:

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();
}

Если вы опустите this -> , компилятор не знать, как обращаться с и , поскольку он может существовать или не существовать во всех экземплярах A . Чтобы сообщить ему, что i действительно является членом A , для любого T используется префикс this -> является обязательным.

Примечание: можно все еще опустить этот -> префикс, используя: локальная переменная

  • Если вы просто хотите чтобы было ясно, что вы вызывают метод / переменную экземпляра

  • Некоторые стандарты кодирования используют подход (2), поскольку они утверждают, что он упрощает чтение кода.

    Пример:
    Предположим, что MyClass имеет переменную-член с именем «count»

    void MyClass::DoSomeStuff(void)
    {
       int count = 0;
    
       .....
       count++;
       this->count = count;
    }
    
    6
    ответ дан 24 November 2019 в 07:30
    поделиться

    Еще один случай - вызов операторов. Например, вместо

    bool Type::operator!=(const Type& rhs)
    {
        return !operator==(rhs);
    }
    

    вы можете сказать

    bool Type::operator!=(const Type& rhs)
    {
        return !(*this == rhs);
    }
    

    Что может быть более читаемым. Другой пример - копирование и обмен:

    Type& Type::operator=(const Type& rhs)
    {
        Type temp(rhs);
        temp.swap(*this);
    }
    

    Я не знаю, почему не написано swap (temp) , но это кажется обычным явлением.

    5
    ответ дан 24 November 2019 в 07:30
    поделиться

    Есть несколько случаев, когда использование this необходимо , а есть другие, где использование указателя this является одним из способов решения проблема.

    1) Доступные альтернативы : Чтобы устранить неоднозначность между локальными переменными и членами класса, , как показано @ASk .

    2) Нет альтернативы: Чтобы вернуть указатель или ссылку на this из функции-члена. Это часто делается (и должно быть сделано) при перегрузке оператор + , оператор- , оператор = и т. Д .:

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

    Это позволяет использовать идиому, известную как « объединение методов », где вы выполняете несколько операций с объектом в одной строке кода. Например:

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

    Некоторые считают это консенсусом, другие считают это мерзостью. Считайте меня в последней группе.

    3) Нет альтернативы: Для разрешения имен в зависимых типах. Это возникает при использовании шаблонов, как в этом примере:

    #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) Доступные альтернативы: Как часть стиля кодирования, для документирования того, какие переменные являются переменными-членами, а не локальными переменными. Я предпочитаю другую схему именования, в которой переменные-члены никогда не могут иметь то же имя, что и локальные. В настоящее время я использую mName для членов и имя для местных.

    чтобы задокументировать, какие переменные являются переменными-членами, а не локальными. Я предпочитаю другую схему именования, в которой переменные-члены никогда не могут иметь то же имя, что и локальные. В настоящее время я использую mName для членов и имя для местных.

    чтобы задокументировать, какие переменные являются переменными-членами, а не локальными. Я предпочитаю другую схему именования, в которой переменные-члены никогда не могут иметь то же имя, что и локальные. В настоящее время я использую mName для членов и имя для местных.

    5
    ответ дан 24 November 2019 в 07:30
    поделиться

    Вам нужно только используйте this->, если у вас есть символ с тем же именем в двух потенциальных пространствах имен. Возьмем, к примеру:

    class A {
    public:
       void setMyVar(int);
       void doStuff();
    
    private:
       int myVar;
    }
    
    void A::setMyVar(int myVar)
    {
      this->myVar = myVar;  // <- Interesting point in the code
    }
    
    void A::doStuff()
    {
      int myVar = ::calculateSomething();
      this->myVar = myVar; // <- Interesting point in the code
    }
    

    В интересных местах кода ссылка на myVar будет ссылаться на локальную (параметр или переменную) myVar. Чтобы получить доступ к члену класса, также называемому myVar, вам необходимо явно использовать this ->.

    4
    ответ дан 24 November 2019 в 07:30
    поделиться

    Другие варианты использования для этого (как я подумал, когда прочитал резюме и половину вопрос ....), игнорируя (плохое) неоднозначность имен в других ответах, если вы хотите преобразовать текущий объект, привязать его к объекту функции или использовать его с указателем на член.

    Приводит

    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 {}
    

    Связывание

    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)();
        }
    }
    

    Надеюсь, это поможет показать другие варианты использования этого элемента, кроме this->.

    4
    ответ дан 24 November 2019 в 07:30
    поделиться

    Я нашел еще один интересный случай явного использования указателя «this» в книге «Эффективный C ++».

    Например, скажем, у вас есть константная функция вроде

      unsigned String::length() const
    

    У вас нет хотите вычислить длину String для каждого вызова, поэтому вы хотите кэшировать его, выполняя что-то вроде

      unsigned String::length() const
      {
        if(!lengthInitialized)
        {
          length = strlen(data);
          lengthInitialized = 1;
        }
      }
    

    Но это не будет компилироваться - вы меняете объект в константной функции.

    Чтобы решить эту проблему, требуется приведение типов ] this в неконстантный this :

      String* const nonConstThis = (String* const) this;
    

    Тогда вы сможете сделать в

      nonConstThis->lengthInitialized = 1;
    
    2
    ответ дан 24 November 2019 в 07:30
    поделиться

    Вам необходимо использовать this для устранения неоднозначности между параметрами / локальными переменными и переменными-членами.

    class Foo
    {
    protected:
      int myX;
    
    public:
      Foo(int myX)
      {
        this->myX = myX; 
      }
    };
    
    3
    ответ дан 24 November 2019 в 07:30
    поделиться

    Существует несколько причин, по которым вам может потребоваться явно использовать указатель this .

    • Когда вы хотите передать ссылку на свой объект какой-либо функции.
    • Когда существует локально объявленный объект с тем же именем, что и объект-член.
    • Когда вы пытаетесь получить доступ к членам зависимых базовых классов .
    • Некоторые люди предпочитают нотацию, чтобы визуально устранять неоднозначность доступа к членам в их коде.
    18
    ответ дан 24 November 2019 в 07:30
    поделиться

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

    5
    ответ дан 24 November 2019 в 07:30
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: