У меня была проблема с matchit, находящим правильную подходящую фигурную скобку в C ++ / C, когда были закомментированные фигурные скобки. Следующие шаги, взятые из этого поста на форуме , написанного этим парнем , решили его для меня, а также в значительной степени объяснили, как все это работает:
Создайте папку ~ / .vim / plugin, если ее там еще нет:
mkdir ~/.vim/plugin
Создайте файл с именем ~ / .vim / plugin / matchit. vim:
vi ~/.vim/plugin/matchit.vim
и следующее содержимое:
runtime macros/matchit.vim
Создайте каталог ~ / .vim / doc, если его там еще нет:
mkdir ~/.vim/doc
Скопируйте /usr/share/vim/vim73/macros/matchit.txt в ~ / .vim / doc /:
cp /usr/share/vim/vim73/macros/matchit.txt ~/.vim/doc/
Откройте vi
vi
и выполните в нем следующее:
:helptags ~/.vim/doc
Убедитесь, что ваш ~ / .vimrc включает одно из следующего:
source $VIMRUNTIME/vimrc_example.vim
или
runtime vimrc_example.vim
или
filetype plugin on
или
filetype plugin indent on
Добавьте в свой 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
Перезапустите Vim.
Обычно этого не требуется, это ->
подразумевается.
Иногда возникает двусмысленность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда явно требуется 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
}
};
Если вы объявляете локальную переменную в методе с тем же именем, что и существующий член, вам придется использовать 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
Обычно это не требуется, это ->
подразумевается.
Иногда возникает двусмысленность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда явно требуется 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;
}
Еще один случай - вызов операторов. Например, вместо
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)
, но это кажется обычным явлением.
Есть несколько случаев, когда использование 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
для членов и имя
для местных. Вам нужно только используйте 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 ->.
Другие варианты использования для этого (как я подумал, когда прочитал резюме и половину вопрос ....), игнорируя (плохое) неоднозначность имен в других ответах, если вы хотите преобразовать текущий объект, привязать его к объекту функции или использовать его с указателем на член.
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;
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->.
Я нашел еще один интересный случай явного использования указателя «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;
Вам необходимо использовать this
для устранения неоднозначности между параметрами / локальными переменными и переменными-членами.
class Foo
{
protected:
int myX;
public:
Foo(int myX)
{
this->myX = myX;
}
};
Существует несколько причин, по которым вам может потребоваться явно использовать указатель this
.
Although I usually don't particular like it, I've seen others use this-> simply to get help from intellisense!