Отправляет email-рассылки с помощью сервиса Sendsay

Программирование. Форум !!!

За 2003-11-11

Re: Новости дискуссионного листа "Программирование. Форум !!!"

Здравствуйте !

> Зрравствуй Vic
> Спасибо за ответ.Т.е.заканчивая обсуждение предидущего вопроса я делаю
> вывод, что вызов базового класса лучше всетаки делать из тела конс
> труктора.
> Теперь вопросы (у меня их много) буду задавать в порядке в котором они у
> меня возникают.
>
> И так создан проект на базе CDialog допустим имя FtpFirst;
> В файле заголовка FtpFirstDlg.h обьявлен класс
> class CFtpFirstDlg:public CDialog
> {
> .....
> static UINT getDownloadFileFunc(LPVOID pParam);//Обьявлена такая функция
> ....
> static CFtpConnection* pFtpConnect;
> CInternetSessionEx* pSession;//и две таких переменных
>
> ....
> void connect(void);
> }
>
> Теперь в файле cpp в функции connect инициализируется сессия а вней
> инициализируется PFtpConnect
> после того как коннект установлен нужный файл найден вызывается процедура
> AfxBeginThread(getDownloadFileFunc,0);
> если функция getDownloadFileFunc не static то транслятор выдает о
> шибку при
> ав этом месте
> CFtpFirstDlg::getDownloadFileFunc(LPVOID pParam)
> {
> .....
> pFtpConnect-> //если тип переменной static то переменная разрешена
> транслятор не выдает ошибки
>
> }
> но при линковке возникает ошибка
> в чем здесь проблема?
>
> Владимир

Все достаточно просто. Функция getDownloadFileFunc действительно должна
быть статической. Дело в том, что в AfxBeginThread должен передаваться
указатель либо на глобальную функцию, либо на статическую функцию-член
класса.

Поясню.

Но сначала небольшое лирическое отступление...

Представьте, что вы пишете программу на чистом C (не C++).

У вас есть некоторые данные в виде структуры. Например :

struct MyStruct
{
int a1;
int a2;
};

Для оперирования с данными вы пишете несколько функций :

void init(MyStruct *pStruct)
{
pStruct->a1 = 0;
pStruct->a2 = 0;
}

void print(MyStruct *pStruct)
{
printf("a1 = %d a2 = %d", pStruct->a1, pStruct->a2);
}

и, наконец, используете эти функции :

MyStruct data;

init(&data);
print(&data);

Здорово, но надо передавать указатель.
Объектно-ориентированные языки программирования решают эту проблему,
передавая этот самый указатель на данные за вас неявным образом.
То есть на C++ можно все вышеизложенное написать так :

struct MyStruct
{
int a1;
int a2;

void init();
void print();
};

void MyStruct::init()
{
a1 = 0;
a2 = 0;
}

void MyStruct::print()
{
printf("a1 = %d a2 = %d", a1, a2);
}

а а потом использовать :

MyStruct data;

data.init();
data.print();

Для компилятора и первый и второй пример практически одинаков.
В обоих случаях в функции init и print первым параметром передается
указатель на структуру данных, только во втором случае - неявно.

Но его можно использовать (например так) :

void MyStruct::init()
{
this->a1 = 0;
a2 = 0;
}

Как вы заметили, в C++ структура также может инкапсулировать
методы как класс. Но чем же тогда класс отличается от структуры
в терминах C++ ?

Можно делать так :

MyStruct data;
data.a1 = 0;

То есть в структуре все переменные по-умолчанию - public;

И вот если объявить не структуру, а класс :

class MyStruct
{
int a1;
int a2;

void init();
void print();
};

И потом объявить объект этого класса и попытаться поюзать методы и
свойства :

MyStruct data;
data.a1 = 0;
data.print();

компилятор ругнется, что a1 и print protected. То есть в классах
методы и свойства по-умолчанию - protected. И еще - сцитается, что
класс принципиально отличается от структуры только одним -
наличием конструктора. Хотя в VC++ пробовал - у структуры тоже
можно написать конструктор.

А теперь - о наших баранах...

Функция (AFX_THREADPROC pfnThreadProc, ... принимает первым
параметром указатель на функцию, тип которого AFX_THREADPROC.

AFX_THREADPROC продекларирован так :

typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID);

То есть этой функции передается только один параметр.

А учтя все вышесказанное,
если в классе декларируется функция :

class CFtpFirstDlg:public CDialog
{
UINT getDownloadFileFunc(LPVOID pParam);
...

Компилятор компилирует код для передачи двух параметров - this и pParam.
И с точки зрения компилятора, прототипы этих функций абсолютно разные.

Поэтому традиционным подходом при решении таких задач является передача
указателя на объект класса в качестве параметра pParam.

То есть в вашем случае чтобы в функции рабочего потока можно было
использовать методы и свойства класса CFtpFirstDlg, функцию
UINT getDownloadFileFunc(LPVOID pParam); надо действительно объявить
как статическую (статические функции практически то же самое, что и
глобальные - в них указатель this не передается, они просто принадлежат
пространству имен класса, членами которого являются) и передавать в нее
укзатель на объект класса.

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

class CFtpFirstDlg:public CDialog
{
.....
static UINT getDownloadFileFunc(LPVOID pParam);//Обьявлена такая функция
....
static CFtpConnection* pFtpConnect;
CInternetSessionEx* pSession;
....

afx_msg void OnButton1();

....
}

UINT CFtpFirstDlg::getDownloadFileFunc(LPVOID pParam)
{
CFtpFirstDlg *pDlg = (CFtpFirstDlg *) pParam;

CStdioFile *pFile = pDlg->OpenURL("http://SoftMaker.fatal.ru");

...

return 0;
}

void CThreadDlg::OnButton1()
{
AfxBeginThread(getDownloadFileFunc, (LPVOID) this);
}

в функции потока параметр приводим к указателю на объект класса, и юзаем
методы и свойства.

Вот так обычно и делают.

Vic.

-*Информационный канал Subscribe.Ru
Написать в лист: mailto:comp.soft.prog.prog-list@subscribe.ru
Отписаться: http://subscribe.ru/member/unsub?grp=comp.soft.prog.prog&email=
http://subscribe.ru/ mailto:ask@subscribe.ru

   2003-11-11 23:31:33 (#19476)

Re: Новости дискуссионного листа "Программирование. Форум !!!"

Зрравствуй Vic
Спасибо за ответ.Т.е.заканчивая обсуждение предидущего вопроса я делаю
вывод, что вызов базового класса лучше всетаки делать из тела конструктора.
Теперь вопросы (у меня их много) буду задавать в порядке в котором они у
меня возникают.

И так создан проект на базе CDialog допустим имя FtpFirst;
В файле заголовка FtpFirstDlg.h обьявлен класс
class CFtpFirstDlg:public CDialog
{
.....
static UINT getDownloadFileFunc(LPVOID pParam);//Обьявлена такая функция
....
static CFtpConnection* pFtpConnect;
CInternetSessionEx* pSession;//и две таких переменных

....
void connect(void);
}

Теперь в файле cpp в функции connect инициализируется сессия а вней
инициализируется PFtpConnect
после того как коннект установлен нужный файл найден вызывается процедура
AfxBeginThread(getDownloadFileFunc,0);
если функция getDownloadFileFunc не static то транслятор выдает ошибку при
ав этом месте
CFtpFirstDlg::getDownloadFileFunc(LPVOID pParam)
{
.....
pFtpConnect-> //если тип переменной static то переменная разрешена
транслятор не выдает ошибки

}
но при линковке возникает ошибка
в чем здесь проблема?

Владимир

-*Информационный канал Subscribe.Ru
Написать в лист: mailto:comp.soft.prog.prog-list@subscribe.ru
Отписаться: http://subscribe.ru/member/unsub?grp=comp.soft.prog.prog&email=
http://subscribe.ru/ mailto:ask@subscribe.ru

   "vlad" 2003-11-11 17:01:18 (#19263)