Почему оператор-> может быть перегружен вручную? - PullRequest
15 голосов
/ 30 мая 2010

Разве не имеет смысла, если p->m был просто синтаксическим сахаром для (*p).m? По сути, каждое написанное мной operator-> могло бы быть реализовано следующим образом:

Foo::Foo* operator->()
{
    return &**this;
}

Есть ли какой-нибудь случай, когда я бы хотел, чтобы p->m означало нечто иное, чем (*p).m?

Ответы [ 5 ]

18 голосов
/ 30 мая 2010

operator->() имеет причудливое различие , неявно вызываемое многократно , в то время как тип возврата допускает это . Самый простой способ показать это с помощью кода:

struct X {
    int foo;
};

struct Y {
    X x;
    X* operator->() { return &x; }
};

struct Z {
    Y y;
    Y& operator->() { return y; }
};

Z z;
z->foo = 42;          // Works!  Calls both!

Я вспоминаю случай, когда такое поведение было необходимо, чтобы позволить объекту вести себя как прокси для другого объекта в контексте, подобном интеллектуальному указателю, хотя я не могу вспомнить детали. Что я помню, так это то, что я мог заставить поведение работать так, как я планировал, используя синтаксис a->b, используя этот странный особый случай; Я не мог найти способ заставить (*a).b работать аналогично.

Не уверен, что это отвечает на ваш вопрос; на самом деле я говорю: «Хороший вопрос, но это даже страннее!»

3 голосов
/ 30 мая 2010

Один из вариантов использования может быть при создании DSL внутри C ++, в соответствии с Boost Karma (хотя, похоже, он не перегружает -> в их библиотеке), где вы полностью измените смысл традиционных операторов C ++. Является ли это хорошей идеей, несомненно, подлежит обсуждению.

1 голос
/ 30 мая 2010

Обычные указатели предлагают p->m и (*p).m, причем p->m является гораздо более распространенным. Если вы разрешите перегрузку только одного из них, это будет несовместимо с типом по умолчанию. Что касается того, почему бы не позволить компилятору переписать его, простой ответ заключается в том, что иногда вы не хотите, чтобы operator-> возвращал T *, где operator * возвращает T &. Разрешение их перегружать отдельно позволяет использовать комбинации, о которых вы не всегда можете думать. Но было бы глупо запретить это, просто потому, что в настоящее время мы не можем думать ни о какой причине, чтобы изменить это. Очень похоже, что вы могли бы иметь класс int128 и оператор перегрузки + = для обозначения возведения в степень вместо этого, если бы вы этого хотели.

0 голосов
/ 30 мая 2010

Я думаю, что он используется для shared_ptr <> в boost (например). Это делает их «похожими» на обычные указатели, хотя они и являются специальными указателями (подсчет ссылок afaik).

0 голосов
/ 30 мая 2010

Возможно, вы захотите выполнить некоторые другие операции, такие как увеличение переменной (подсчет доступа) или даже некоторые проверки безопасности и т. Д. С другой стороны, мне никогда не приходилось перегружать оператор-> ...

...