Перевантаження операторів доступу членів ->,. *


129

Я розумію , більшість перевантаження операторів, за винятком операторів доступу члена ->, .*, і ->*т.д.

Зокрема, що передається цим операторським функціям, а що потрібно повернути?

Як функція оператора (наприклад operator->(...)) знає, до якого члена відноситься? Чи може це знати? Це навіть потрібно знати?

Нарешті, чи є якісь міркування щодо суперечності, які потрібно враховувати? Наприклад, при перевантаженні чогось подібного operator[], як правило, вам знадобиться як версія const, так і non-const. Чи вимагають оператори доступу членів const та non-const версії?


1
Я вважаю, що вищевказаний C ++ - Faq стосується всіх запитань Q у вищезгаданому питанні.
Alok Зберегти

constі не- constверсії operator->не потрібні , але надання обох може бути корисним.
Фред Фоо

1
Дивіться також: yosefk.com/c++fqa/operator.html
György Andrasek

9
@Als: FAQ не пояснює, як перевантажувати ->*і .*. Насправді вони навіть не згадують про них! Я відчуваю, що вони рідко зустрічаються в FAQ, але я з радістю пов'язую це запитання з FAQ. Будь ласка, не закривайте це як манеру поширених запитань!
sbi

@sbi, я просто не знайшов посилання на це запитання у вашому (дивовижному) FAQ, і в кінцевому підсумку задав повторне запитання. Не могли б ви зробити це більш очевидним? (вибачте, якщо це вже очевидно).
П я

Відповіді:


144

->

Це єдиний справді хитрий. Це повинна бути нестатична функція члена, і вона не бере аргументів. Повернене значення використовується для здійснення пошуку члена.

Якщо значення повернення - це інший об'єкт типу класу, а не покажчик, то наступний пошук членів також обробляється operator->функцією. Це називається "поведінкою збивання". Мова зв'язує operator->дзвінки, поки останній не поверне вказівник.

struct client
    { int a; };

struct proxy {
    client *target;
    client *operator->() const
        { return target; }
};

struct proxy2 {
    proxy *target;
    proxy &operator->() const
        { return * target; }
};

void f() {
    client x = { 3 };
    proxy y = { & x };
    proxy2 z = { & y };

    std::cout << x.a << y->a << z->a; // print "333"
}

->*

Цей лише хитрий у тому, що в цьому немає нічого особливого. Чи не перевантажений версія вимагає об'єкт покажчика на тип класу на лівому боці і об'єкт покажчика типу елемента праворуч. Але коли ви перевантажуєте це, ви можете приймати будь-які вподобані вам аргументи і повертати все, що завгодно. Це навіть не повинно бути нестатичним членом.

Іншими словами, це один просто нормальний бінарний оператор , як +, -, і /. Дивіться також: Чи вільний оператор -> * перевантажує зло?

.* і .

Вони не можуть бути перевантажені. Вже є вбудоване значення, коли ліва частина класу типу. Можливо, було б мало сенсу мати можливість визначити їх за вказівником з лівого боку, але комітет з мовної розробки вирішив, що це буде більше заплутаним, ніж корисним.

Перевантаження ->, ->*, .і .*може заповнити тільки в тих випадках , коли вираз буде визначено, воно ніколи не може змінити значення виразу , яке буде дійсним, без перевантаження.


2
Ваше останнє твердження не зовсім правдиве. Наприклад, ви можете перевантажувати newоператора, навіть якщо він дійсний навіть тоді, коли він не перевантажений.
Метт

6
@Matt добре, newзавжди перевантажений, або правила перевантаження насправді до нього не застосовуються (13.5 / 5: Функції розподілу та розміщення, оператор новий, оператор новий [], оператор видалення та оператор видалення [], повністю описані в 3.7 +0,4. атрибути і обмеження , знайдені в іншій частині цього підпункту не поширюються на них , якщо явно не вказані в 3.7.4.) Але перевантажень унарних &або бінарний файл &&, ||або ,, або додавання перевантажень operator=або перевантажень просто про що - небудь для незадані тип перерахування, може змінити значення виразу. Уточнив заяву, дякую!
Potatoswatter

41

Оператор -> особливий.

"Він має додаткові, нетипові обмеження: він повинен повернути об'єкт (або посилання на об'єкт), який також має оператор перенаправлення вказівника, або він повинен повернути вказівник, який може бути використаний для вибору, на що вказує стрілка оператора перенаправлення. " Брюс Еккель: Мислення CPP Vol-one: оператор->

Додатковий функціонал передбачений для зручності, тому вам не доведеться телефонувати

a->->func();

Ви можете просто зробити:

a->func();

Це робить оператора -> відмінним від інших перевантажень оператора.


3
Ця відповідь заслуговує на більше кредиту, ви можете завантажити книгу Еккеля за цим посиланням, а інформація знаходиться у главі 12 першого тома.
П я

26

Ви не можете перевантажувати доступ учасників .(тобто друга частина того, що ->робить). Однак ви можете перевантажити унарні разименованія оператора *(тобто перша частина того, що ->робить).

Оператор C ++ ->- це об'єднання двох кроків, і це зрозуміло, якщо ви вважаєте, що x->yце рівносильно (*x).y. C ++ дозволяє налаштувати, що робити з (*x)частиною, коли xце екземпляр вашого класу.

Смисловість для ->перевантаження дещо дивна, оскільки C ++ дозволяє або повернути звичайний покажчик (що він буде використовуватися для пошуку загостреного об'єкта), або повернути екземпляр іншого класу, якщо цей клас також надає ->оператора. У другому випадку пошук оберегованого об'єкта продовжується з цього нового примірника.


2
Чудове пояснення! Я здогадуюсь, що це означає те ж саме для ->*, як це еквівалентно формі (*x).*?
Бінго

10

->Оператор не знає , що елемент на який вказує на, він просто надає об'єкт для виконання фактичного доступу учасника на.

Крім того, я не бачу причин, чому ви не можете надати версії const та non-const.


7

Коли ви перевантажуєте оператор -> () (тут ніяких аргументів не передано), те, що компілятор насправді робить, викликає -> рекурсивно, поки він не поверне фактичний покажчик на тип. Потім використовується правильний член / метод.

Це корисно, наприклад, для створення класу розумних покажчиків, який інкапсулює фактичний покажчик. Перезавантажений оператор-> викликається, робить все, що він робить (наприклад, блокування для безпеки потоку), повертає внутрішній покажчик, а потім компілятор викликає -> для цього внутрішнього вказівника.

Що стосується constness - на нього відповідають у коментарях та інші відповіді (ви можете, і повинні, надати і те, і інше).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.