Эзотерические операторы C

#c

Вопрос:

Какова цель следующих эзотерических операторов C ?

Указатель на элемент

 ::*
 

Привязать указатель к элементу с помощью указателя

 ->*
 

Привязать указатель к элементу по ссылке

 .*
 

(ссылка)

Комментарии:

1. Что бы ни говорила википедия, ::* это не оператор.

Ответ №1:

Указатель на элемент позволяет иметь указатель, относящийся к определенному классу.

Итак, допустим, у вас есть класс контактов с несколькими телефонными номерами.

 class contact
{
    phonenumber office;
    phonenumber home;
    phonenumber cell;
};
 

Идея заключается в том, что если у вас есть алгоритм, который должен использовать номер телефона, но решение о том, какой номер телефона следует принимать вне алгоритма, указывает на то, как решить проблему:

 void robocall(phonenumber contact::*number, ...);
 

Теперь абонент robocall может решить, какой тип телефонного номера использовать:

 robocall(amp;contact::home, ...);    // call home numbers
robocall(amp;contact::office, ...);  // call office number
 

.* и ->* вступайте в игру, как только у вас появится указатель. Так что внутри robocall вы бы сделали:

 contact c = ...;
c.*number;    // gets the appropriate phone number of the object
 

или:

 contact *pc = ...;
pc->*number;
 

Комментарии:

1. В InformIT есть читаемое руководство по указателям на участников .

2. Здесь есть хороший пример этого: msdn.microsoft.com/en-us/library/k8336763.aspx

3. Да, указатели на элементы довольно удобны — я широко использую их для сериализации в/из потоков байтов и наборов результатов базы данных. Вроде как заканчивается отражением бедняка. С помощью указателей на элементы (поля и методы) вы можете легко настроить структуры данных, которые позволяют динамически манипулировать типами с очень небольшим количеством статических знаний (обычно помогает иметь общую базу и некоторые доступные методы отправки в стиле посетителя).

Ответ №2:

Такого оператора нет ::* и никогда не было. Я не знаю, где ты его взял.

Что касается ->* и .* — это операторы разыменования для указателей типа указатель на элемент.

 struct S {
  int i;
};

int main() {
  int S::*pi = amp;S::i; // pointer of pointer-to-member type

  S s;
  S* ps = amp;s;

  s.*pi = 0; // operator `.*` used
  assert(s.i == 0);

  ps->*pi = 1; // operator `->*` used
  assert(s.i == 1);
}
 

Что касается того, что такое указатели на участников… что говорит по этому поводу ваша любимая книга на C ?

Комментарии:

1. Я получил ::* из википедии, указанной в качестве ссылки на мой вопрос.

2. ::* отлично компилируется в g .

3. @Neil G: Что именно «отлично компилируется в g «?

4.@Neil G: :: является оператором, потому что так сказано в стандарте, и потому :: что токен играет роль оператора в синтаксисе C . ::* не является оператором, потому что стандарт не упоминает об этом, когда перечисляет операторы, и потому ::* что при анализе C нет маркера. int x = 5 -2; компилирует, не означает - , что является оператором.

5. @Neil G: Во-первых, ::* в ответе Сэмюэля нет оператора. Единственное место, где вы можете найти ::* его ответ (как и в моем), — это декларации. В объявлениях нет такого понятия, как «операторы», даже если что-то может выглядеть как оператор. Когда вы видите int i = 1; в коде, = бит не является оператором, это просто синтаксический элемент объявления.

Ответ №3:

Они относятся к указателям на элементы и указателям на функции-члены.

 struct Foo {
    int a() { return 1; }
    int b() { return 2; }
    int c;
};

int main() {
    Foo f;
    f.c = 3;

    typedef int (Foo::*member_fn)(); // pointer-to-member-function
    typedef int (Foo::*data_member); // pointer-to-member

    member_fn mf = amp;Foo::a;
    (f.*mf)(); // calls the member function pointed to by mf. returns 1
    mf = amp;Foo::b;
    (f.*mf)(); // This time, returns 2, since mf points to b
    Foo *fp = amp;f;
    (fp->*mf)(); // same thing, via pointer to f instead of object/reference f.

    data_member dm = amp;Foo::c;
    f.*dm; // is 3
    f.*dm = 5;
    f.c;  // is now 5.

    Foo f2; // another instance
    f2.c = 12;
    f2.*dm;  // is 12. Same pointer-to-member, different object.
}
 

Хотя это может выглядеть так, ::* это не оператор. Это :: * оператор и модификатор типа оператора рядом друг с другом. Чтобы доказать это, не прибегая к чтению стандарта, попробуйте добавить пробелы: :: * компилирует, . * не делает и не делает -> * .

Что касается того, для чего они на самом деле полезны — тот же принцип, что и указатели функций. Вы бы не использовали их, как я описал выше, в ситуации, когда вы могли бы просто вызвать функцию по имени, но вы можете передать их в качестве параметров или вернуть их из функций, сохранить их или выбрать один из нескольких на основе сложной логики.

Если это поможет, я полагаю, что синтаксис выбран таким образом , что, хотя .* это неделимый единый оператор, вы можете представить, что *dm «означает» c , элемент, на который указывает dm. Так что если dm указывает на c , то f.*dm это то же f.c самое, что и .

Ответ №4:

Ознакомьтесь с разделом C FAQ Lite, посвященным указателям на функции-члены. Найдите конкретные «операторы», о которых вы говорите (в большинстве браузеров Ctrl-F открывает диалоговое окно поиска/поиска, которое позволяет вам искать текст на веб-странице), и это должно помочь вам лучше понять ситуацию.

Ответ №5:

Упрощенный ответ — эти операторы позволяют вызывать функции-члены как «обычные» функции (по крайней мере, это выглядит одинаково с точки зрения конечного пользователя) . Пример реального мира — они часто используются в различных реализациях обратного вызова.

Ответ №6:

Они позволяют иметь указатели на функции-члены (и переменные-члены), которые привязаны к определенному экземпляру класса.

Указатели на функции-члены могут быть полезны для таких вещей, как облегченные реализации шаблона состояния. Как правило, в любое время, когда вы хотите изменить поведение объекта с течением времени, не прибегая к отключению всего объекта, вы можете рассмотреть возможность использования указателей на функции-члены.

Указатели на переменные-члены можно использовать, если вы хотите, например, реализовать универсальный алгоритм для поиска в массиве структур записи, имеющей определенное значение для данного поля.