Чому ви не можете перевантажити "." оператор в C ++?


79

Було б дуже корисно мати можливість перевантажити. в C ++ і повертає посилання на об'єкт.

Ви можете перевантажити operator->і , operator*але неoperator.

Чи є для цього технічна причина?


4
Чи можете ви навести приклад того, коли ви хочете замінити "." оператор?
Toon Krijthe

4
Як правило, варіант використання - це "розумні посилання". Своєрідний проксі.
ddaa

2
@Gamecat: Прочитайте цю пропозицію, щоб додати можливість перевантаження, operator.і в operator.*ній є кілька прикладів.
Манкарс

1
@ToonKrijпростори навколо .дозволені, тому, можливо, якийсь розумний, але жахливий динамічний диспетчерський хак, який дозволяє висловити крапковий продукт як matrix1 . matrix2.
mwcz

Відповіді:


62

Дивіться цю цитату Бьярна Струструпа :

Оператор. (крапка) в принципі може бути перевантажена за допомогою тієї ж техніки, що і для ->. Однак це може призвести до питань про те, чи призначена операція для перевантаження об'єкта. або об'єкт, на який посилається. Наприклад:

class Y {
public:
    void f();
    // ...
};

class X {    // assume that you can overload .
    Y* p;
    Y& operator.() { return *p; }
    void f();
    // ...
};

void g(X& x)
{
    x.f();    // X::f or Y::f or error?
}

Цю проблему можна вирішити кількома способами. На момент стандартизації не було очевидно, який шлях буде найкращим. Детальніше див. У Розробка та еволюція C ++ .


Повна цитата з TDaEoC ++ у моїй відповіді.
ddaa

15
У мене є спокуса проголосувати за плагіат / перефарбування. Цитуючи, цитуйте дослівно, не налаштовуйте. І використовуйте формати цитат.
Себастьян Мах

2
Прикладом є просто неясність дозволу на перевантаження, що вказує на необхідність більш ретельного програмування (див .: stackoverflow.com/questions/13554606/… ) Ця ситуація не повинна служити причиною, щоб не перевантажуватисьoperator .
slashmais

@slashmais Ні. Обґрунтування operator.явної паралелі з operator->. І як ви могли зробити перевантаження дозволу?
curiousguy

Тільки щоб зауважити, що пізніше Бьярн Страуструп висловився за операторську крапку і навіть просунув пропозицію щодо цього, яка, мабуть, ще не була прийнята: http://www.open-std.org/jtc1/sc22/wg21/ docs / papers / 2015 / n4477.pdf - як це вже додав @emlai як коментар до питання
Амір Кірш,

52

Строструп сказав, що C ++ повинен бути розширюваною, але не мінливою мовою.

Оператор точки (доступ до атрибута) вважався занадто близьким до ядра мови, щоб дозволити перевантаження.

Див . Дизайн та еволюція C ++ , сторінка 242, розділ 11.5.2 Розумні посилання .

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

Тоді я вважав наступні аргументи беззаперечними: Якщо objце об’єкт класу, то це obj.mмає значення для кожного члена mкласу цього об’єкта. Ми намагаємось не робити мову змінною, перевизначаючи вбудовані операції (хоча це правило порушується =з крайньої необхідності та для унарних &).

Якби ми дозволили перевантаження .класу X, ми не змогли б отримати доступ до членів Xзвичайними засобами; нам довелося б використовувати вказівник та ->, але, ->і, &можливо, також було б перевизначено. Я хотів розширювану мову, а не змінну.

Ці аргументи вагомі, але не остаточні. Зокрема, у 1990 р. Джим Адкок запропонував дозволити перевантаження оператора . саме таким, яким ->є оператор .

"Я" в цій цитаті - Бьярн Струструп. Ви не можете бути авторитетнішими за це.

Якщо ви хочете по-справжньому зрозуміти C ++ (як у "чому це так"), вам слід абсолютно прочитати цю книгу.


28

Stroustrup має відповідь на це питання :

Оператор. (крапка) в принципі може бути перевантажена за допомогою тієї ж техніки, що і для ->. Однак це може призвести до питань про те, чи призначена операція для перевантаження об'єкта. або об'єкт, на який посилається. Наприклад:

class Y {
public:
    void f();
    // ...
};
class X {   // assume that you can overload .
    Y* p;
    Y& operator.() { return *p; }
    void f();
    // ...
};
void g(X& x)
{
    x.f();  // X::f or Y::f or error?
}

Цю проблему можна вирішити кількома способами. На момент стандартизації не було очевидно, який шлях буде найкращим. Для отримання більш детальної інформації див. D&E .


1
Дивіться мій коментар до відповіді Антона
slashmais

1

Це дуже легко зрозуміти, якщо ви пройдете внутрішній механізм виклику функції оператора, скажімо, комплекс класів може мати два члени r для реальної частини та i для уявної частини. Скажімо, Комплекс C1 (10,20), C2 (10,2) // ми припускаємо, що в класі вже є конструктор двох аргументів. Тепер, якщо ви пишете C1 + C2 як оператор, тоді компілятор спробує знайти перевантажену версію оператора + на комплексному номері. Тепер ми припускаємо, що я перевантажую + оператор, тому C1 + C2 внутрішньо перекладається як c1.operator + (c2) Тепер припустимо, що для істот часу ви можете перевантажити '.' оператора. так що тепер подумайте про наступний виклик C1.disp () // відображати вміст складного об’єкта. Тепер спробуйте представити як внутрішнє представлення C1.operator. (------) , створені абсолютно безладні речі. Ось чому ми не можемо перевантажити ''. оператора


1
Деякі люди кажуть, що внутрішній переклад не повинен називати перевантаженимoperator.
curiousguy

Дивіться пропозицію C ++ щодо того, як це може бути корисним і не таким брудним: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf
Амір Кірш,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.