Ответ 1
Тип этого указателя есть либо ClassName *
, либо const ClassName *
, в зависимости от того, проверяется ли он внутри метода non-const или const класса ClassName
. Указатель this
не является lvalue.
class ClassName {
void foo() {
// here `this` has `ClassName *` type
}
void bar() const {
// here `this` has `const ClassName *` type
}
};
Наблюдение, о котором вы говорили выше, вводит в заблуждение. Указатель this
не является значением lvalue, что означает, что он не может иметь тип ClassName * const
, т.е. Он не может иметь const
справа от *
. Не-lvalues типа указателя не может быть const или не const. Просто нет такой концепции на языке С++. То, что вы наблюдали, должно быть внутренним причудом конкретного компилятора. Формально это неверно.
Вот соответствующие цитаты из спецификации языка (выделение)
9.3.2 Этот указатель
В теле нестатической (9.3) функции-члена ключевое слово this выражение prvalue, значение которого является адресом объекта для который вызывается функцией. Тип этого в членной функции класс X является X *. Если функция-член объявлена const, тип это const X *, если функция-член объявлена изменчивой, тип этого является изменчивым X *, и если объявлена функция-член const volatile, тип этого - константа volatile X *. [Примечание: таким образом, в функция-член const, объект, для которого вызывается функция доступен через путь доступа к const. -end note]
Не стоит ничего, что в С++ 98/С++ 03 раз несколько компиляторов использовали внутренний реализационный трюк: они интерпретировали свои указатели this
как постоянные указатели, например. ClassName *const
в непостоянном методе класса ClassName
. Это, по-видимому, помогло им обеспечить немогитильность this
. GCC и MSVC, как известно, использовали эту технику. Это был безобидный трюк, поскольку на уровне языка this
не было lvalue, и его константа была необнаруживаема. Этот дополнительный const
обычно обнаруживается только в диагностических сообщениях, выпущенных компилятором.
Однако с появлением ссылок rvalue в С++ 11 стало возможным обнаружить этот дополнительный const
по типу this
. Например, следующий код действителен в С++ 11
struct S
{
void foo() { S *&&r = this; }
};
Однако он, как правило, не сможет скомпилировать в реализациях, которые все еще используют вышеупомянутый трюк. С тех пор GCC отказался от этой техники. MSVС++ все еще использует его (как и VS2017), что предотвращает компиляцию вышеуказанного полностью корректного кода в MSVС++.