Когда у вас есть язык, который по своей сути предназначен для «переносимого ассемблера», вы не пытаетесь скрыть детали реализации от пользователя. Конечно, компилятор может определить, что в выражении a.b
рассматриваемый a
является указателем. Ты можешь? Надежно? Все время? В волосатом, сложном коде? И разве вы не можете представить себе ситуацию, при которой неспособность быстро заметить, что a
является указателем, может стать проблемой?
Перестаньте думать в терминах «трудно написать» и начните думать в терминах « легко читать ». (Да, я знаю. Это противоречит мифам программистов на C!) Вы будете читать код на пару порядков чаще, чем писать его.
Да, двусмысленность возникает из-за возможности переопределения обоих операторов. Лучшим примером могут служить общие указатели. Общий указатель может использоваться с операторами . и ->, и оба имеют разное значение.
С помощью -> вы получаете доступ к объекту, на который указывают, а с помощью . вы получаете доступ к членам самого общего указателя.
For instance:
class MyObject {
public:
void myFunction() {}
};
boost::shared_ptr<MyObject> ptr;
ptr.use_count(); // calls use_count, which is a member of boost::shared_ptr.
ptr->myFunction(); // calls MyObject::myFunction, as the operator-> is overriden
Вы действительно хотите, чтобы компилятор «понял это сам»? Если это так, то следующее будет оценивать то же самое (предполагая, что p
является указателем на структуру с членом x
):
(*p).x;
p.x
Если разыменование указателя выполняется неявно там, должно ли оно быть неявным везде ? Подумайте:
int* p;
int i = p; // should dereferencing be implicit here as well?
Я думаю, что это будет намного сложнее, чем наличие двух отдельных операторов.
Также может быть полезно наличие двух операторов, которые помогут отслеживать, сколько у вас уровней косвенного обращения. Конечно, оператор ->
для этого не является строго необходимым, поскольку p-> x
эквивалентен (* p) .x
, но делает код стал немного понятнее и удобнее для чтения.
C ++ позволяет игнорировать оператор ->
. Если у вас есть класс интеллектуального указателя, например std :: auto_ptr
, одна и та же переменная может поддерживать оба .
и ->
, на которых вы используете .
для доступа к элементам auto_ptr
и ->
для доступа к элементам указателя, который он содержит.
Оператор -> - это просто более простой способ ссылаться на метод или член объекта по его указателю, вместо использования чего-то вроде (* p) .member или (* p) .method.
Пример:
MyClass * MyObj;
MyObj-> method (); лучше читать и понимать, чем (* MyObj) .method ();
Оба fo-> bar
и (* fo) .bar
делают одно и то же!
Язык просто предоставляет оператор для непрямого доступа, а именно стрелку ( ->
), и обрабатывает ее как один символ.