Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Запретить менять спецификатор доступа


Автор: SABROG 10.3.2010, 15:32
Может показаться, что вопрос по Qt, но на самом деле по C++ ;)

В Qt есть класс QThread. Часто делают ошибки, переопределяя метод run() из protected секции в своих наследниках и выносят его в public секцию. Затем вызывают thread->run(), вместо thread->start(). Вопрос в том, как запретить наследнику менять спецификатор доступа или вызывать метод, чтобы при этом оставалась возможность его переопределять.

Автор: mes 10.3.2010, 15:36
Цитата(SABROG @  10.3.2010,  14:32 Найти цитируемый пост)
как запретить наследнику менять спецификатор доступа или вызывать метод,

написать крупными буквами в документации ))

Добавлено через 1 минуту и 55 секунд
или заменить run на что то типа doOnRun smile

Автор: SABROG 10.3.2010, 15:42
Цитата(mes @  10.3.2010,  15:36 Найти цитируемый пост)
или заменить run на что то типа doOnRun smile

Ага doNotRunJustReimplement() ;)

Цитата(mes @  10.3.2010,  15:36 Найти цитируемый пост)
написать крупными буквами в документации ))

Предложил троллям, но ведь у нас мало кто документацию читает.

Автор: SenkraD 10.3.2010, 15:43
SABROG,  как вариант сделать шаблонную обёртку или
примменить CRTP (я более за 2-й вариант), в которой вызывать QThread::start

имхо, тут без шаблоноа никак!!!

Можеш примерный код накидать того, что получить хочеш?

Автор: SABROG 10.3.2010, 15:49
Цитата(SenkraD @  10.3.2010,  15:43 Найти цитируемый пост)
Можеш примерный код накидать того, что получить хочеш?


Код

class MyThread : public QThread
{
Q_OBJECT
public:
    MyThread(QObject* parent) : QThread(parent)
    {
    }

    ~MyThread() {}

    void run()
    {
        exec();
    }
}


Хочу, чтобы при таком наследовании компилятор выругнулся и не дал мне переместить run() из protected в public.

Автор: 17dufa 10.3.2010, 19:11
SABROG, а сделать его private и virtual? не подойдет? можно тока переопределять, вызвать - фиг.

Автор: mes 10.3.2010, 21:36
Цитата(17dufa @  10.3.2010,  18:11 Найти цитируемый пост)
а сделать его private и virtual? не подойдет? можно тока переопределять, вызвать - фиг.

разве ?  http://codepad.org/NBCI8JST    

Автор: andrew_121 10.3.2010, 22:04
Цитата(SenkraD @  10.3.2010,  15:43 Найти цитируемый пост)
имхо, тут без шаблоноа никак!!!

 smile 
но есть одно НО!
Qt-шная сигнал-слотовая модель не работает с шаблонами smile 

Автор: SABROG 11.3.2010, 00:40
А я бы и на шаблонный вариант посмотрел.

Автор: mes 11.3.2010, 00:59
Цитата(SABROG @  10.3.2010,  23:40 Найти цитируемый пост)
А я бы и на шаблонный вариант посмотрел. 

можно например так :
Код

template <class T>
class ThreadT {
 T& m_worker;

 public:
    ThreadT (T& worker) : m_worker(worker) {}

    void start ();
    void terminate ();

  private:
    void run() { if (!m_worker ()) terminate();  }
};

struct Worker 
{
   Worker (int, double, char);
   bool operator () () {}

};

int main ()
{
     Worker worker (1, 2., 'A');
     ThreadT<Worker> thread(worker);
     thread.start();
}


Автор: andrew_121 11.3.2010, 01:06
угу. только работать не будет.

Автор: SABROG 11.3.2010, 01:53
Цитата(mes @ 11.3.2010,  00:59)
можно например так :

А переопределение run() где тут?

Автор: mes 11.3.2010, 02:39
Цитата(andrew_121 @  11.3.2010,  00:06 Найти цитируемый пост)
угу. только работать не будет.

а поподробнее ? что Вам в коде не понравилось то smile


Цитата(SABROG @  11.3.2010,  00:53 Найти цитируемый пост)
А переопределение run() где тут? 

в роли Run выступает функтор, в примере Worker ..
Если хочется Run можно им заменить operator (), но по сути это лишнее smile



Автор: andrew_121 11.3.2010, 02:43
Цитата(mes @  11.3.2010,  02:39 Найти цитируемый пост)
а поподробнее ? что Вам в коде не понравилось то

дело в том, что это дело, нужно для работы в Qt. а для работы метаобъектной системы, нельзя использовать шаблоны.

Добавлено @ 02:44
Цитата(mes @  11.3.2010,  02:39 Найти цитируемый пост)
что Вам в коде не понравилось то

мне то все понравилось. но вот moc, ваши старания не оценит smile 
mes, если интересно, мы с SABROG подискутировали по этому поводу тут: http://forum.vingrad.ru/index.php?showtopic=293991&view=findpost&p=2113872

Автор: mes 11.3.2010, 03:12
Цитата(andrew_121 @  11.3.2010,  01:43 Найти цитируемый пост)
мне то все понравилось. но вот moc, ваши старания не оценит smile 

а зачем шаблоному классу ThreadT сигнал-слоты ? А Worker подходит под вкус moca, так что, имхо, полный порядок smile

Автор: andrew_121 11.3.2010, 03:32
наверное я вас не совсем верно понял.
или вы...

вот я смотрю на ваш код, и абсолютно не въезжаю, как тут использовать QThread ? smile 
нет, т.е. я представляю, но moc откажется работать. а вы утверждаете что нет. в общем запутали вы меня...

Добавлено через 3 минуты и 49 секунд
Код

template <class T>
class ThreadT: public QThread {
 T& m_worker;
 public:
    ThreadT (T& worker) : m_worker(worker) {}
    void start ();
    void terminate ();
  protected:
    void run() {                  <<< это метод предка, который нужно реализовать.
        if (!m_worker ()) terminate();
    }
};
struct Worker 
{
   Worker (int, double, char);
   bool operator () () {}
};
int main ()
{
     Worker worker (1, 2., 'A');
     ThreadT<Worker> thread(worker);
     thread.start();
}

я понимаю это так.
но повторюсь, моc`у это не понравится.

Автор: mes 11.3.2010, 10:05
Цитата(andrew_121 @  11.3.2010,  02:32 Найти цитируемый пост)
вот я смотрю на ваш код, и абсолютно не въезжаю, как тут использовать QThread 

значит я не до конца понял задание.. Я думал вопрос состоит в иной, чем на данный момент имеется, организации библиотеки smile
т.е пример был ориентирован на избавление от перегрузки Run у QThread.
smile
Можно конечно и без шаблонов, с использованием Функционального объекта с виртуальной функцией,
Код

struct QThreadObj 
{
   virtual ThreadOdj () {}
   virtual bool operator () {}
// или
   virtual void operator () (QThread&) {} 
};

class QThreadFO : QThread {
    ThreadObj& m_obj;
 public:
    QThread (QThreadObj& obj) : m_obj(worker) {}
    void start ();
    void terminate ();
  protected:
    void run() { 
        if (!m_obj ()) terminate();
    }
// или
    void run() { m_obj (*this);  }
};

ну и использовать так :
Код

struct Worker  : QThreadObj
{
   Worker (int, double, char);
   bool operator () () {}
};
int main ()
{
     Worker worker (1, 2., 'A');
     QThreadFO thread(worker);
     thread.start();
}


Автор: SABROG 11.3.2010, 12:11
Цитата(mes @  11.3.2010,  10:05 Найти цитируемый пост)
Можно конечно и без шаблонов, с использованием Функционального объекта с виртуальной функцией,


А если этот код разделить на 2 части, то какая из них будет принадлежать библиотеке, а какую будет писать сам пользователь класса?

Еще такой вопрос, не будет ли проблемы с функциональным объектом, когда библиотека попытается получить адрес функции для передачи этого адреса в API целевой системы?

Автор: mes 11.3.2010, 12:32
Цитата(SABROG @  11.3.2010,  11:11 Найти цитируемый пост)
А если этот код разделить на 2 части, то какая из них будет принадлежать библиотеке, а какую будет писать сам пользователь класса?

ну так разделено же.. верхний блок кода условно-библиотечный , а нижний условно-пользовательский.


Цитата(SABROG @  11.3.2010,  11:11 Найти цитируемый пост)
Еще такой вопрос, не будет ли проблемы с функциональным объектом, когда библиотека попытается получить адрес функции для передачи этого адреса в API целевой системы?

А зачем ей (АПИ) адрес функции фо (функционального объекта) ? пусть Thread свою функцию и отдает, в которой будет вызывать уже фо smile


Автор: SABROG 11.3.2010, 12:37
Понял. А как организовать доступ к членам класса QThread из функционального объекта? Делать их friend'ами?

Автор: mes 11.3.2010, 12:48
Цитата(SABROG @  11.3.2010,  11:37 Найти цитируемый пост)
. А как организовать доступ к членам класса QThread из функционального объекта? 

у thread есть публичный интерфейс (start, terminate, priority.. ) - вот им и нужно пользоваться.. 
Если вопрос как получать thread в котором сейчас работает фо, то смотрите часть кода после // или
Если ж речь о  данных необходимых для работы фо, то они должны быть членами фо, а не thread`a, что и пытался показать конструктором в коде.

Вобщем вопрос непонятен.. если ответил не на то , перефразируйте, плиз
smile


Автор: SABROG 11.3.2010, 13:05
В принципе у QThread есть несколько protected членов, с которыми необходимо работать. Например exec(), чтобы запускать или не запускать локальный цикл событий.

Как я понял "operator ()" что-то типа безымянного метода? Это мало чем отличается от "obj.someMethod()". В некотором смысле это тоже самое, что и ссылка на метод класса &MyClass::myMethod() и ссылки на экземпляр объекта класса. А если вообще утрировать, то это обычный callback? smile

Автор: mes 11.3.2010, 13:35
Цитата(SABROG @  11.3.2010,  12:05 Найти цитируемый пост)
есть несколько protected членов, с которыми необходимо работать. Например exec(), 

ну а  к thread`у она какое отношение имеет ? Qt запихнула все в один класс к ним и обращайтесь smile

Цитата(SABROG @  11.3.2010,  12:05 Найти цитируемый пост)
Как я понял "operator ()" что-то типа безымянного метода? Это мало чем отличается от "obj.someMethod()". 

ага, просто удобно вызывать.. можно любую другую функцию, или даже их набор.
smile

Цитата(SABROG @  11.3.2010,  12:05 Найти цитируемый пост)
. В некотором смысле это тоже самое, что и ссылка на метод класса &MyClass::myMethod() и ссылки на экземпляр объекта класса. 

зачем ерез окно лезть, когда дверь открыта smile это обычный объект который можно использовать синтаксически подобно функции, т.е. obj();


Цитата(SABROG @  11.3.2010,  12:05 Найти цитируемый пост)
А если вообще утрировать, то это обычный callback? smile

Callback это применение. любая функция вызваная полиморфно является по сути колбяком smile


Автор: SABROG 11.3.2010, 13:42
Цитата(mes @  11.3.2010,  13:35 Найти цитируемый пост)
ну а  к thread`у она какое отношение имеет ? Qt запихнула все в один класс к ним и обращайтесь


Пользовательский объект должен быть на базе QObject'a, чтобы обеспечить межпоточное общение между объектами, да и доступ нужен к сигналам и слотам объекта QThread, чтобы подключение сделать.

Автор: mes 11.3.2010, 13:50
Цитата(SABROG @  11.3.2010,  12:42 Найти цитируемый пост)
Пользовательский объект должен быть на базе QObject'a, чтобы обеспечить межпоточное общение между объектами, да и доступ нужен к сигналам и слотам объекта QThread, чтобы подключение сделать. 

пользовательский объект это фо , вот он на базе QObjecta, если нужно, пусть будет smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)