Что означает синтаксис С++ и почему он работает?

Я просматривал источник OpenDE, и я наткнулся на какое-то странное использование синтаксиса оператора индексирования массива '[]' в классе. Здесь приведен упрощенный пример синтаксиса:

#include <iostream>

class Point
{
public:
    Point() : x(2.8), y(4.2), z(9.5) {}

    operator const float *() const
    {
        return &x;
    }

private:
    float x, y, z;
};

int main()
{
    Point p;
    std::cout << "x: " << p[0] << '\n'
              << "y: " << p[1] << '\n'
              << "z: " << p[2];
}

Вывод:

x: 2.8
y: 4.2
z: 9.5

Что здесь происходит? Почему этот синтаксис работает? Класс Point не содержит перегруженных operator [], и здесь этот код пытается сделать автоматическое преобразование в float где-нибудь.

Я никогда раньше не видел такого рода использования - он определенно выглядит необычным и удивительным, если не сказать больше.

Спасибо

Ответы

Ответ 1

p преобразуется неявно в const float* const, что указывает на x. Итак, *p - x, *(p+1) - y и т.д. Конечно, это довольно странная идея (и запутанная!). Обычно предпочтительнее хранить x, y и z в массиве и иметь функцию для получения всего массива, если они действительно хотят сделать это таким образом.

Ответ 2

Идея здесь - предоставить доступ к членам Точки либо индексом, либо именем. Однако, если вы хотите сделать это, вам будет лучше перегружать operator[] что-то вроде этого:

struct Point { 
    float x, y, z;

    float &operator[](size_t subscript) { 
        switch(subscript) {
            case 0: return x;
            case 1: return y;
            case 2: return z;
            default:  throw std::range_error("bad subscript");
        }
    }
};

Таким образом, если компилятор добавляет отступы между поплавками, он все равно будет работать - и любой, кто может читать С++, должен понимать это без каких-либо проблем.

Ответ 3

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

typedef struct {
   CGFloat m11,m12,m13,m14;
   CGFloat m21,m22,m23,m24;
   CGFloat m31,m32,m33,m34;
   CGFloat m41,m42,m43,m44;
} CATransform3D;

Вы можете удобно ссылаться на каждую ячейку по имени, но вы можете также обходить вокруг указателя на m11 всюду (и C увидит вашу структуру как массив, m11 - первый элемент) и перебирает все элементы.