[C++] как написать operator[]

Sanjaz



class CPoint
{
private:
double m_values[3];

public:
const double& operator[](unsigned int index) const
{
std::cout<<"const\n";
return m_values[index];
}

double& operator[](unsigned int index)
{
std::cout<<"simple\n";
return m_values[index];
}
};
int main(int argc, char *argv[])
{
CPoint point;

double v=point[1];
point[0]=0.5;
return 0;
}


Почему вызывается 2 раза double& operator[](unsigned int index)?
Что здесь не правильно?

ppplva


const CPoint point; point[0];


вызовет второй оператор

Sanjaz

А как сделать так, чтобы
на double v=point[0] вызывался const double& operator[](unsigned int index) const,
а на point[0]=5 вызывался double& operator[](unsigned int index)?

ppplva

Насколько я знаю, никак.

bleyman

Если ты уверен что это действительно тебе нужно, можешь извратнуться. Один сделать [int], другой [unsigned int] и в явном виде писАть
double v=point[(int)0]
point[(unsigned int)0]=5
Правда я не уверен, что это сработает. В шарпе сработало бы точно.

ppplva

Тогда зачем вообще операторы ? Сделать 2 метода типа double read(int) и write(int, double).

ifani

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

psihodog

Ну это-то как раз можно реализовать, если operator[] будет возвращать хитрый класс, у которого определён operator= на запись в файл, а operator char (int, double, etc) -- на чтение из файла. Экземпляр вспомогательного класса создаётся на выходе из метода operator[] исходного класса, и в параметр ему пихается позиция файле и дескриптор файла. Ну что-то вроде такого:


#include <stdio.h>
class io_byte {
private:
FILE *const f;
unsigned long pos;
public:
io_byte(FILE *f1, unsigned long pos1): f(f1 pos(pos1) {}
operator char const {fseek(f,pos,SEEK_SET); return fgetc(f);}
const io_byte &operator=(char c) const {fseek(f,pos,SEEK_SET); fputc(c,f); return *this;}
};
class file_vector {
private:
FILE *f;
public:
file_vector(const char *fname) {f= fopen(fname,"r+");}
~file_vector {fclose(f);}
io_byte operator[](unsigned long i) {return io_byte(f,i);}
};
int main
{
file_vector f("aaa");
char c=f[3]='A';
printf("%c%c\n",cchar)f[4]);
return 0;
}


А по возвращаемому значению функции не специализируются (AFAIK) .

ifani

ну вот и решение проблемы топика :о)

ppplva

Некрасивое решение. Страшное и неэффективное.
Хотя для каких-то случаев оно применимо.

mirt1971

Нормальное решение... Особенно если учесть что тут все будет инлайниться. Никакого оверхеда по сравнению с просто fseek fgetc. Хотя я бы например сделал mmap и не парился.

rosali

Чего страшного-то, снаружи ведь конфетка, а что внутри - пофиг. И совершенно справедливо, что overhead-а нет.

ppplva

Я заменил FILE* на char*, fgetc на [], и так далее. По сравнению с обычным char[] этот класс работает раз в 6 медленнее.
gcc -O2 -fomit-frame-pointer -funroll-loops -finline-functions
Что еще стоит включить ?

evgen5555

Ты это остро почувствуешь тогда, когда места на диске под создание файла не останется или диск будет попросту закрыт на запись. В чем же дело, спросит тогда конечный пользователь. Почему оператор индекса не работает? Ебта?

Marinavo_0507

Исключение вылетит.

bleyman

Да, и вправду конечному пользователю будет очень удивительно, откуда прилетает ИО ексепшен про то что диск фулл, если он использует буфер мапящийся на файл! "В чем же дело?" - спросит он себя, - "почему же не работает мой ненаглядный оператор индекса?"

psihodog

да вы чего ребята?..
класс был написан только из спортивного интереса.
такой стиль программирования на С++ (когда происходит разврат в пользу "красоты" кода) я не считаю удачным.
насчёт эксэпшенов... вы не поверите, что произойдёт если запустить программу, на создав ей предварительно файл "aaa".

rosali

А какой смысл сравнивать fgetc с обычным char[] ? Надо сравнивать C-ную программу, использующую fgetc и C++-ную программу, в которой fgetc спрятан под operator []

psihodog

Насколько я понимаю, он сравнил работу с массивом напрямую и через эти классы, заменив их функциональность с файлового ввода-вывода, на ввод/вывод в массив. В общем довольно логично для оценки оверхеда.
Компилировал gcc с опцией -S, действительно компилятор вставляет туда много всякой фигни... Не знаю, существует ли компилятор, который скомпилит это дело нормально, и вообще, возможен ли он. Но я никаких препятствий не вижу пока.

rosali

Не знаю чего там gcc... Вот что генерит моя VS.NET 2004:


class Char
{
char & chr;
public:
Char(char & chr)
: chr(chr) {}
void operator = (char chr)
{
this->chr = chr;
}
operator char
{
return(chr);
}
};
class CharArray
{
char * data;
public:
CharArray(int size)
: data(new char[size])
{}
~CharArray
{
delete[] data;
}
Char operator [](int index)
{
return(Char(data[index];
}
};
int __declspec(noinline) test(int size)
{
00401000 push esi
CharArray a(size);
00401001 mov esi,dword ptr [esp+8]
00401005 push edi
00401006 push esi
00401007 call operator new[] (401BE8h)
0040100C add esp,4
for(int i=0; i<size; i++)
0040100F xor ecx,ecx
00401011 test esi,esi
00401013 jle test+1Dh (40101Dh)
a[i] = i;
00401015 mov byte ptr [ecx+eax],cl
00401018 inc ecx
00401019 cmp ecx,esi
0040101B jl test+15h (401015h)
int s = 0;
0040101D xor edi,edi
for(int i=0; i<size; i++)
0040101F xor ecx,ecx
00401021 test esi,esi
00401023 jle test+30h (401030h)
s+= a[i];
00401025 movsx edx,byte ptr [ecx+eax]
00401029 add edi,edx
0040102B inc ecx
0040102C cmp ecx,esi
0040102E jl test+25h (401025h)
return(s);
00401030 push eax
00401031 call operator delete[] (401C12h)
00401036 add esp,4
00401039 mov eax,edi
0040103B pop edi
0040103C pop esi
}
0040103D ret


Куда уж лучше то?
Оставить комментарий
Имя или ник:
Комментарий: