есть класс Buffer, в котором определена private переменная buf
class Buffer {
private buf;
....
}Задача такая:
необходимо написать функцию чтения ( неважно, откуда, например, из файла) непосредственно в эту переменную. При этом очень не хочется обьявлять новый класс - читальщик, в котором эта функция была бы дружественной к классу Buffer.Предполагаю слелать это следующим образом:
int Buffer::read( int _param, int ( *_reader)(...)) { ...... }
В ф-цию Buffer::read передается указатель на функцию чтения. Внутри ф-ции read мы имеем доступ к закрытым переменным класса и каким-то образом пихаем в ф-цию _reader эту переменную.Можно ли так?
Если можно, то как?WBR, Dvorkin
>есть класс Buffer, в котором определена
>private переменная buf
>class Buffer {
>private buf;
>....
>}
>
>Задача такая:
>необходимо написать функцию чтения ( неважно,
>откуда, например, из файла) непосредственно
>в эту переменную. При этом
>очень не хочется обьявлять новый
>класс - читальщик, в котором
>эта функция была бы дружественной
>к классу Buffer.
>
>Предполагаю слелать это следующим образом:
>int Buffer::read( int _param, int (
>*_reader)(...)) { ...... }
>В ф-цию Buffer::read передается указатель на
>функцию чтения. Внутри ф-ции read
>мы имеем доступ к закрытым
>переменным класса и каким-то образом
>пихаем в ф-цию _reader эту
>переменную.
>
>Можно ли так?
>Если можно, то как?
>
>WBR, DvorkinДа, функция _reader имеет переменное число параметров.
>>есть класс Buffer, в котором определена
>>private переменная bufТип buf не указан - считаем его char*.
>>class Buffer {
>>private buf;
>>....
>>}
...
>>int Buffer::read( int _param, int (
>>*_reader)(...)) { ...... }
>>В ф-цию Buffer::read передается указатель на
>>функцию чтения.И buf и read являются членами класса Buffer.
>>Внутри ф-ции read
>>мы имеем доступ к закрытымНу естественно.
>>переменным класса и каким-то образом
>>пихаем в ф-цию _reader эту
>>переменную.И чем ЭТОТ ПОДХОД отличается от принципа друзей ?
Только тем, что кроме buf'а твой reader ничего другого не увидит.
>>
>>Можно ли так?Почему же нет, только криво это, ИМХО( см. ЗЫЖ )
>>Если можно, то как?
>>Объяви функцию
char* Buffer::getBufPrt() { return buf };
например. После чего ты сможешь адрес переменной таскать куда хочешь и как хочешь. НО: ты сначала получишь вне класса указатель на его закрытый член, передашь его какой-то ф-ции чтения, потом указатель на ту функцию чтения будешь передавать в другой член класса. Бег по кругу.>>WBR, Dvorkin
>
>Да, функция _reader имеет переменное число
>параметров.Не понял. Если не знаешь как сделать перерменное число параметров, читай man stdarg. В других случаях - объясни в чем проблема.
ЗЫЖ
Прежде всего я всегда имею класс работы с файлами. Делать его 10 минут, а пользоваться можно всегда. Но если идти по твоему пути я сделал бы так:
В класссе Buffer:
Buffer& operator << ( const char* str )
{
//Контроль размеров данных !
...
//
buf[0] = 0;
strcat( buf, str );
return *this;
}
После чего извне класса Buffer можно писАть в эту переменную что угодно, и как тебе нравится:
...
Buffer* ptrBuf = new Buffer...;
const char aaa[] = "Test writing";
...
ptrBuf << aa;
...
При таком подходе ты избавляешься от перетаскивания указателей - эти операции САМЫЕ опасные в С ибо указатели обладают очень неприятными свойствами: теряться и портиться - ,а все чтения из файла остаются вне класса и не путаются под ногами.
hi!Мы не поняли друг друга.
Есть класс Buffer, внутри которого переменная private: char *buf;
Есть некоторые 2 функции ввода-вывода, про которых известно только что они возвращают число прочитанных или записанных байт и один из параметров каждой функции - Buffer.
==> Необходимо сделать общие функции Buffer::read/Buffer::write,
которые принимали бы в качестве параметра указатель на функцию чтения, переменную Buffer (в/из которой читать/писать) и собственное переменное число других параметров. Так, как вызов делается внутри Buffer ==> эта функция чтения/записи может работать непосредственно с приватным указателем на char, который определен внутри Buffer.
Проблема кроется вот в чем...
1) как обнаружить среди параметров ф-ции Buffer::read переменную типа class Buffer и подсунуть вместо нее Buffer::buf (пусть этот параметр может быть только один) ?
2) как взять все эти парамтры (c этой замененной переменной) и пихнуть их в вызов функции ввода вывода, указатель на которую передается.Код должен, по моему разумению, выглядеть примерно так:
class Buffer {
private:
char *buf;
int datalen;
.....
public:
int read( int ( *_reader(...), ...)) {
/* заменяем единственный параметр типа Buffer на Buffer::buf */
/* делаем вызов ф-ции ввода/вывода: */
int breaded = ( *_reader)( /* аргументы, переданные ф-ции Buffer::read с замененным параметром типа Buffer на Buffer::buf */);
this->datalen += breaded;
return( breaded);
}}
/* где многоточия - переменное число параметров. */
Buffer buff;
buff.read( &recv, sockfd, buff, 1024, options);
^^^^
после чего имеем в буфере добавочку - полученную строку. :)
Как раз мысль для того, чтобы не заниматься ненужными выделениями/копированиями памяти.
А если делать как Вы предложили - функцию, возвращающую указатель на Buffer::buf, то это снимает идею защищенности данных.По всей видимости, тут необходимо выполнять операции непосредственно со стеком... Но ничего в явном виде не сказано ни в книжках, ни в мануале по stdarg.
Есть мысли?
WBR, Dvorkin
-----------------------------------------------
>>>есть класс Buffer, в котором определена
>>>private переменная buf
>
>Тип buf не указан - считаем
>его char*.
>
>>>class Buffer {
>>>private buf;
>>>....
>>>}
>...
>>>int Buffer::read( int _param, int (
>>>*_reader)(...)) { ...... }
>>>В ф-цию Buffer::read передается указатель на
>>>функцию чтения.
>
>И buf и read являются членами
>класса Buffer.
>
>>>Внутри ф-ции read
>>>мы имеем доступ к закрытым
>
>Ну естественно.
>
>>>переменным класса и каким-то образом
>>>пихаем в ф-цию _reader эту
>>>переменную.
>
>И чем ЭТОТ ПОДХОД отличается от
>принципа друзей ?
>Только тем, что кроме buf'а твой
>reader ничего другого не увидит.
>
>
>>>
>>>Можно ли так?
>
>Почему же нет, только криво это,
>ИМХО( см. ЗЫЖ )
>
>>>Если можно, то как?
>>>
>
>Объяви функцию
>char* Buffer::getBufPrt() { return buf };
>
>например. После чего ты сможешь адрес
>переменной таскать куда хочешь и
>как хочешь. НО: ты сначала
>получишь вне класса указатель на
>его закрытый член, передашь его
>какой-то ф-ции чтения, потом указатель
>на ту функцию чтения будешь
>передавать в другой член класса.
>Бег по кругу.
>
>>>WBR, Dvorkin
>>
>>Да, функция _reader имеет переменное число
>>параметров.
>
>Не понял. Если не знаешь как
>сделать перерменное число параметров, читай
>man stdarg. В других случаях
>- объясни в чем проблема.
>
>
>ЗЫЖ
>Прежде всего я всегда имею класс
>работы с файлами. Делать его
>10 минут, а пользоваться можно
>всегда. Но если идти по
>твоему пути я сделал бы
>так:
>В класссе Buffer:
>Buffer& operator << ( const char*
>str )
>{
> //Контроль размеров данных
>!
> ...
> //
> buf[0] = 0;
>
> strcat( buf, str
>);
> return *this;
>}
>После чего извне класса Buffer можно
>писАть в эту переменную что
>угодно, и как тебе нравится:
>
>...
>Buffer* ptrBuf = new Buffer...;
>const char aaa[] = "Test writing";
>
>...
>ptrBuf << aa;
>...
>При таком подходе ты избавляешься
>от перетаскивания указателей - эти
>операции САМЫЕ опасные в С
>ибо указатели обладают очень неприятными
>свойствами: теряться и портиться -
>,а все чтения из файла
>остаются вне класса и не
>путаются под ногами.
>А если делать как Вы предложили - функцию, возвращающую указатель на Buffer::buf, то это снимает идею защищенности данных.Как раз ЭТО я и не предлагал. ЭТО был вариант реализации ВАШЕЙ идеи. Я предлагал перегрузить оператор "<<" для занесения даных в буфер.
>
>По всей видимости, тут необходимо выполнять
>операции непосредственно со стеком... Но
>ничего в явном виде не
>сказано ни в книжках, ни
>в мануале по stdarg.
>
Именно, в man stdarg и описывается действие макрокоманд
...
va_list pvar;void va_start(va_list pvar, void parmN);
(type *) va_arg(va_list pvar, type);
void va_copy(va_list dest, va_list src);
void va_end(va_list pvar);
....
Параметры функции передаются через стек и работа с адресами параметсров и есть работа со стеком. На русском эта байда хорошо описана у Чана.
Можно также глянуть man va_start etc.>Есть мысли?
Если коротко - класс сокетов должен быть базовым для классов буферов, протоколов представления и пр. А функция чтения/записи из/в сокет(а) объявляется виртуальной, после чего каждый порожденный класс может ее переопределять по-своему.
ЗЫ
Я не сторонник программирования ради искусства, но ИМХО, в д.с. множественное наследование С++ как раз то что требуется.