Есть несколько вещей, чтобы рассмотреть здесь:
Что такое const
: указатель или pointee?
Давайте рассмотрим различия между этими различными декларациями.
int x, y;
int * p = &x; // 0
const int * p = &x; // 1
int const * p = &x; // 2
int * const p = &x; // 3
const int * const p = &x; // 4
int const * const p = &x; // 5
(0) означает, что p
может измениться (p = &y;
ОК) и то, что он указывает (x
) может быть изменен с помощью p
(*p = y;
ОК).
(1) и (2) эквивалентны и означают, что p
может измениться (p = &y;
ОК) и то, что он указывает (x
) не может быть изменен с помощью p
(*p = y;
ошибка).
(3) означает, что p
не может изменить (p = &y;
ошибка) и то, что она указывает на (x
) может быть изменен с помощью p
(*p = y;
ОК)
(4) и (5) эквивалентны и означает, что p
не может измениться (p = &y;
- это ошибка), и то, на что он указывает (x
), не может быть изменено с помощью p
(*p = y;
- это ошибка).
простой способ запомнить это смотрит на *
и думать, что он разделяет объекты на константность, то есть,
(а) const
перед тем *
(например const int * [...]
или int const * [...]
) означает заостренный предмет (тип int
) - const
; и
(б) после того, как const
*
(например [...] * const p [...];
) означает, что указатель const
и не может быть изменен.
Что произойдет, если функция возвращает объект const
?
Рассмотрим:
class some_class;
const some_class a(); // equivalent to 'some_class const a();'
someclass b();
const int c(); // equivalent to 'int const c();'
int d();
Тогда (при условии, some_class
имеет оператор доступного присваивания) имеем:
some_class x;
a() = x; // illegal : the returned object is const
b() = x; // OK : the returned object is not const
Это естественно полагать, что c()
и d()
ведут себя так же, но это не:
c() = 0; // illegal
d() = 0; // also illegal!!!
Причина в том, что если функция возвращает фундаментальный тип (например, int
, bool
, char
, любой тип указателя, ...), то возвращенный объект не может быть назначен. Поэтому , возвращающий const
объект фундаментального типа, ведет себя так же, как возвращать неконстантный один.
Как насчет перегрузки по типу возврата?
Рассмотрим
int f(); // first overload.
double f(); // second overload.
Это незаконно. Мы не можем перегружать только возвращаемый тип. Одна из причин заключается в том, что мы всегда можем игнорировать объект, возвращаемый функцией. Например, если разрешена перегрузка по типу возврата, то какая перегрузка f
будет вызываться ниже?
int main() {
f(); // which f?
return 0;
}
Отвечая на вопрос ...
Рассмотрим первую декларацию
AnotherClass* const pointer() const;
Из того, что мы видели, это означает, что pointer()
возвращает const
объект типа AnotherClass*
(указатель тип). Так как тип указателя является фундаментальным типом, функция pointer
выше ведет себя так же, как если бы он был объявлен как
AnotherClass* pointer() const;
, которая является второй перегрузки. Это первая причина, почему эти две перегрузки не имеют смысла. Но это лишь слабая причина по сравнению с тем, что следует.
Когда я говорю «ведет себя одинаково», я не имею в виду «эквивалент». Тип возврата двух перегрузок отличается. Как мы видели, мы не можем перегружать только возвращаемый тип. Это незаконно, и код не компилируется.
это Гарантирует ли мне, что кто-то не может изменить m_pointer памяти указал?
Нет, опять же, как перегруженные ведут себя так же, и возвращает указатель на объект, который может быть изменен с помощью этого указателя. То, что вы хотите, это:
const AnotherClass* pointer() const { return m_pointer; }
// or
// AnotherClass const* pointer() const { return m_pointer; }
Обратите внимание на const
слева от *
.
Вы хотите, чтобы переменная-член 'm_pointer' оставалась неизменной или указывала память? –
Память указал. Спасибо, я не задал точного вопроса. – Eugene