Можно ли переопределить оператор доступа к массиву для указателей на объект в С++?

Я пытаюсь сделать рефакторинг кода и столкнулся с проблемой. В программе есть менеджер данных, который возвращает указатели на массивы структур как void*. Один из новых типов данных вместо одного указателя на массив структур имеет два указателя на массивы чисел. Проблема в том, что весь код обработки выполняется путем доступа к array[index].qwTimestamp и array[index].snSample, которые являются общими для всех типов записей.

Я думал, что переопределение оператора доступа к массиву ( [] ), как показано ниже, может решить проблему:

class ADRec {

public:
    ADRec(unsigned __int64* ts, __int32* data, unsigned index = 0): mTimestamps(ts), mDataPoints(data), mIndex(index) {

        qwTimeStamp = mTimestamps[mIndex];
        snSample = mDataPoints[mIndex];

    }
    ADRec operator[](unsigned i) {
        return ADRec(mTimestamps, mDataPoints, i);

    }
    unsigned __int64 qwTimeStamp;
    __int32 snSample;

private:
    unsigned __int64* mTimestamps;
    __int32* mDataPoints;
    unsigned mIndex;
};

Этот подход отлично работает, если вы используете объект:

unsigned __int64 ts[] = { 2, 3, 4, 5};
__int32 data[] = {4, 6, 8, 10};

ADRec tmp =  ADRec(ts, data, 0);

ASSERT(tmp[0].qwTimeStamp == 2);
ASSERT(tmp[0].snSample == 4);
ASSERT(tmp[1].qwTimeStamp == 3);
ASSERT(tmp[1].snSample == 6);

Но не работает, если вы используете указатель на объект:

unsigned __int64 ts[] = { 2, 3, 4, 5};
__int32 data[] = {4, 6, 8, 10};

ADRec* tmp =  new ADRec(ts, data, 0);

ASSERT(tmp[0].qwTimeStamp == 2);
ASSERT(tmp[0].snSample == 4);
ASSERT(tmp[1].qwTimeStamp == 3); //fails
ASSERT(tmp[1].snSample == 6); //fails

C++ индексирует указатель при вызове tmp[1] и, таким образом, указывает на случайную память.

Можно ли переопределить способ, которым С++ индексирует указатель на объект, или какой-либо другой механизм, который позволит достичь той же цели?


person bsruth    schedule 27.08.2009    source источник
comment
Любой идентификатор, начинающийся с двойного подчеркивания, зарезервирован стандартом. Не используйте '__int32' и т. д. См. stackoverflow.com/questions/228783/   -  person Martin York    schedule 27.08.2009
comment
Эта программа будет использоваться в VS2008, только в среде Windows, поэтому она не соответствует строго стандарту. Но это полезно знать на будущее.   -  person bsruth    schedule 27.08.2009
comment
@Martin Зарезервировано стандартом ДЛЯ РЕАЛИЗАЦИИ. __int32 и др. являются частью реализации MS, поэтому их вполне можно использовать, если переносимость не является проблемой.   -  person    schedule 27.08.2009
comment
@bsruth Если вы создаете для Windows, используйте MinGW и не __int64, а long long. GCC лучше следует стандарту   -  person user877329    schedule 28.03.2012


Ответы (2)


Нет, это невозможно — указатели считаются встроенными, поэтому их операторы не могут быть перегружены. Однако вы, безусловно, можете создавать классы интеллектуальных указателей (классы, которые действуют как указатели, но с дополнительными возможностями) и перегружать их операторы — взгляните, например, на реализацию std::auto_ptr в вашем компиляторе.

person Community    schedule 27.08.2009
comment
Я согласен с этим, создайте свой собственный класс указателя и перегрузите доступ к массиву. Также вы можете перегрузить оператор адреса исходного класса, чтобы вернуть свой собственный указатель. - person Sumudu Fernando; 27.08.2009

Сначала попробуйте разыменовать указатель:

ADRec* tmp =  new ADRec(ts, data, 0);

ASSERT(tmp[0][1].qwTimeStamp == 3);
// or
ASSERT((*tmp)[1].qwTimeStamp == 3);
person Darryl    schedule 27.08.2009
comment
К сожалению, это не сработает, так как все остальные функции обработки ожидают реальный массив записей. Я должен был бы указать особый случай для этого объекта, чего я пытаюсь избежать. - person bsruth; 27.08.2009