Russian Qt Forum
Май 11, 2024, 11:11 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: 1 ... 120 121 [122] 123 124 ... 140
1816  Разное / Говорилка / Re: ЧТо должно быть в багаже программиста при устройстве на работу : Февраль 21, 2011, 14:06
В данный момент я работаю на фирме кодером. Пишу на Qt под Windows и Ubuntu. Год тому назад писал на Visual Basic. Времени на изучение чего то нового не хватает катастрофически так как ещё учусь в универе на 3-ем курсе, но не хочется останавливаться только на данных языках программирования. Я хочу выкраивать драгоценное время на изучение ещё чего нибудь и не хочу обжечся выбрав невостребованное, так как технологии не стоят на одном месте.
Я жду советов в тех областях, которые будут ещё перспективны долгие годы. Те проекты которые сейчас уже существуют, но всё же продолжают совершенствоваться и в будущем может ещё сделают революцию, а не просто умрут.
Я думаю что я сделал правильный выбор в сторону С++.
А какие примерно нужно знать алгоритмы, такой банальный вопрос? Может посоветуете книги, сайты.
Какие советы: рыться в чужих кодах и тем самым набирать опыт кодинга? Изобретать свои велосипеды и не использовать готовые решения? Какие разделы математики необходимо подтянуть? И вообще трудно ли будет мне в будущем если у меня туго с математикой?

Как говорится:
Фотографирует не фотоаппарат, а фотограф..

Это я к тому, что ставить такие вопросы как: а что выбрать: Nikon или Canon - не хорошо, это даже не этично и не проффесионально..
Будете ставить такие вопросы и пытаться искать на них ответы - убъёте сразу двух зайцев:
1) Своё драгоценное время
2) Так и останетесь кодером

Не надо делать из технологии культ, учитесь мыслить абстрактно и учитесь для себя в первую очередь, а не для ради того что через N лет устроится в компанию X и писать с использованием технологии Y
1817  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 21, 2011, 00:49
Вобщем остановился на варианте BRE: отнаследовать receiver от trackable (он же в прошлом spy), т.е. на схеме используемой в libsigc++.
Это означает, что объект который получает сигналы (receiver) должен быть отнаследован от класса trackable. trackable - автоматически разрывает соединение, если receiver будет уничтожен.

Выглядит это так:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
/* Класс A испускает сигналы */
class A
{
public:
   A() {}
 
   ssc::signal<void, std::string> my_signal;
 
   void run() {
       my_signal("Hello Word!");
   }
};
 
/* Класс B  содержит слоты, поэтому он должен отнаследоваться от trackable */
class B : public ssc::trackable
{
public:
   B() {}
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << std::endl;
   }
 
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << std::endl;
   }
};
 
int main()
{
   B *b = new B;
   A *a = new A;
 
   connect(a->my_signal, b, &B::slot1);
   connect(a->my_signal, b, &B::slot2);
 
   a->run();
 
   delete b;
   delete a;
 
   return 0;
}
 
 

Сам механизм сигнал-слот здесь реализован по следующей схеме:
1) Класс base_signal:
Код
C++ (Qt)
template <class T_return, class T_arg> class base_signal
 
Чисто абстрактный класс, реализующий интерфейс:
Код
C++ (Qt)
virtual T_return operator() (const T_arg &) const = 0;
virtual bool valid() const = 0;
 

2) Класс signal:
Код
C++ (Qt)
template <class T_return, class T_arg> class signal
 
Знает о всех соединениях со слотами: имеет список (std::list) соединений (manager_connection) являющихся потомками base_signal.
Имеет перегруженный оператор
Код
C++ (Qt)
T_return operator() (const T_arg &arg) const
 
 
в котором перебирается весь список соединений и для каждого объекта manager_connection вызывается свой переопределённый virtual T_return operator() (const T_arg &) const.

3) Класс manager_connection:
Код
C++ (Qt)
template <class T_receiver, class T_return, class T_arg>
class manager_connection : public base_signal<T_return, T_arg>
 
наследуется от класса base_signal и реализует весь функционал.

4) Класс trackable и trigger:
Код
C++ (Qt)
class trigger
{
public:
   trigger() : _flag(true) {}
   void set(bool flag) { _flag = flag; }
   bool get() const { return _flag; }
 
private:
   bool _flag;
};
 
class trackable
{
public:
   trackable() {
       spy = smart_ptr<trigger>(new trigger);
   }
   virtual ~trackable() {
       spy->set(false);
   }
   smart_ptr<trigger> spy;
};
 
trigger - простой класс имеющий два состояния: true - receiver жив, false - уничтожен
Класс trackable - обёртка над trigger, причём trigger заворачивается в умный указатель, который знает сколько других указателей ссылаются на объект. smart_ptr уничтожит объект если число ссылок counter == 1.
manager_connection также содержит
Код
C++ (Qt)
private:
   T_receiver *_receiver; // указатель на receiver
   smart_ptr<trigger> _spy; // шпион, он же trackable
   ...
 


При вызове одного из 4 конструктора  manager_connection происходит следующее:
Код
C++ (Qt)
manager_connection(signal<T_return, T_arg> &s, T_receiver *obj, function_type_4 slot) {
       _receiver = obj;  // копируем указатель
       _spy = _receiver->spy;  /* копируем шпиона, который вкурсе что происходит с receiverОМ
                                               по средством функции bool get() const */

       _slot_4 = slot;
       _index = 4;
       s.connect(this);  // Заносим данное соединение в список соединений нашего сигнала
   }
 
 

Конечно, в пользовательском коде реально используется только два класса: signal и trackable
и ещё один из вариантов перегруженной функции connect:
Код
C++ (Qt)
template <class T_receiver, class T_return, class T_arg>
void connect(signal<T_return, T_arg> &s, T_receiver *obj, T_return (T_receiver::*slot)(T_arg)) {
   new manager_connection<T_receiver, T_return, T_arg>(s, obj, slot);
}
 

в которой просто создаётся объект manager_connection и передаются все аргументы.

Как то так..
 
Выкладываю для тестирования файл проекта.
Немного причесал код, сейчас вроде всё работает адекватно))
 
1818  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 20, 2011, 16:26
А что если я хочу посылать сигналы объектам разных классов и принимать сигналы от объектов разных классов? И не думать о том каким именно объектам мне слать и получать до того момента когда наступет нужда создать соединение (уже в самом пользовательском коде)? 
А в чем помеха? Объект создается с пустыми контейнерами sender'ов (receiver'ов), connect (который так или иначе неизбежен) их заполняет
Помеха в том, что в контейнере должны будут находится объекты одного класса.
Либо сделать один абстрактный класс, но тогда придётся писать интерфейс на все случаи жизни, что не есть гут)
Идея в том, что общаться могут объекты совершенно разных классов. Задаётся лишь общий шаблон функции сигнала и слота.

Или как Вы имеете в виду?
1819  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 20, 2011, 15:00
Переписал smart_ptr, как предложил brankovic
Вроде сейчас утечек нет:
Код
C++ (Qt)
#ifndef SMART_PTR_H
#define SMART_PTR_H
 
namespace ssc {
 
template <class T>
class smart_ptr
{
public:
   smart_ptr();
   smart_ptr(const smart_ptr<T> &other);
   smart_ptr(T *p);
   ~smart_ptr();
 
   bool is_null() const;
   T* operator->() const;
   T& operator*() const;
   T* get() const;
 
   smart_ptr<T> &operator=(const smart_ptr<T> &p);
 
private:
   T *_obj;
   int *_counter;
 
   void try_destroy();
   smart_ptr<T> &operator=(T*);
};
 
template <class T>
inline smart_ptr<T>::smart_ptr()
   : _obj(0), _counter(0)
{
}
 
template <class T>
inline smart_ptr<T>::smart_ptr(const smart_ptr<T> &other)
   : _obj(other._obj), _counter(other._counter)
{
   if (_counter)
       (*_counter)++;
}
 
template <class T>
inline smart_ptr<T>::smart_ptr(T *p)
   : _obj(p), _counter(new int(1))
{
}
 
template <class T>
inline void smart_ptr<T>::try_destroy()
{
   if (!_obj)
       return;
 
   if ((*_counter) == 1) {
       delete _counter;
       _counter = 0;
       delete _obj;
       _obj = 0;
   }
}
 
template <class T>
inline smart_ptr<T>::~smart_ptr()
{
   try_destroy();
}
 
template <class T>
inline bool smart_ptr<T>::is_null() const
{
   return !_obj;
}
 
template <class T>
inline T* smart_ptr<T>::operator->() const
{
   return _obj;
}
 
template <class T>
inline T& smart_ptr<T>::operator*() const
{
   return *_obj;
}
 
template <class T>
inline T* smart_ptr<T>::get() const
{
   return _obj;
}
 
template <class T>
inline smart_ptr<T>& smart_ptr<T>::operator=(const smart_ptr<T> &p)
{
   if (_obj != p._obj) {
       try_destroy();
       _counter = p._counter;
       _obj = p._obj;
 
       if (_counter)
           (*_counter)++;
   }
   return *this;
}
 
template <class T>
inline smart_ptr<T>& smart_ptr<T>::operator=(T*)
{
   return *this;
}
 
template <class T>
inline bool operator==(const T *o, const smart_ptr<T> &p)
{
   return o == p.operator->();
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p, const T *o)
{
   return p.operator->() == o;
}
 
 
template <class T>
inline bool operator==(T *o, const smart_ptr<T> &p)
{
   return o == p.operator->();
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p, T *o)
{
   return p.operator->() == o;
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p1, const smart_ptr<T> &p2)
{
   return p1.operator->() == p2.operator->();
}
 
template <class T>
inline bool operator!=(const T *o, const smart_ptr<T> &p)
{
   return o != p.operator->();
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p, const T *o)
{
   return p.operator->() != o;
}
 
 
template <class T>
inline bool operator!=(T *o, const smart_ptr<T> &p)
{
   return o != p.operator->();
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p, T *o)
{
   return p.operator->() != o;
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p1, const smart_ptr<T> &p2)
{
   return p1.operator->() != p2.operator->();
}
 
}
 
#endif // SMART_PTR_H
 
Как сделать теперь его тред-сейф ?

Так какой вариант: со шпионом (он же trackable в libsigc++) или через умные указатели использовать? Как идеалогически правильнее?
1820  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 20, 2011, 13:50
Следующий шаг - это наследование класса recivera от класса spy, вместо создания его экземпляра и можно переименовывать spy в trackble.  Улыбающийся
Подмигивающий Но всё же эти две реализации схемы сигнал-слот отличаются)
Идея отнаследоваться от spy это хорошо, мы теперь уже явно в коннект не будем передавать шпиона.. 

А если делать это по простому/народному, не связываясь ни с какими указателями? Ну у объекта 2 контейнера указателей - кому он посылает и кто ему посылает. Деструкторы вычеркивают из этих контейнеров, оператор = может копировать контейнеры, а может и нет (как нравится). Ну "навести песики" типа
Код
C++ (Qt)
class CMyClass : public CSignalReceiver, public CSignalSender {..
 

А что если я хочу посылать сигналы объектам разных классов и принимать сигналы от объектов разных классов? И не думать о том каким именно объектам мне слать и получать до того момента когда наступет нужда создать соединение (уже в самом пользовательском коде)? 
1821  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 20, 2011, 12:30
Цитировать
Чем не нравится такой ptr:

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

Почему бы не выкинуть is_killer и вместо bool is_valid не сделать int counter? Завладев указателем счётчик увеличиваем, потеряв его (через деструктор или operator=) счётчик уменьшаем. Последний владелец это тот, кто опустит счётчик до нуля, тогда можно удалить и счётчик и T.
Да, Вы правы, я малость перемудрил с ptr. Вариант с каунтером гораздо лучше.
У меня просто в голове крутилась идея что убить объект должен именно тот, кто им первым завладеет..

Цитировать
как раз хочется другой вариант. smart_ptr всё равно понадобится, но чтобы спрятать его внутрь
 
Другой вариант заклюсается в том, что мы создаём в класса receivera некий объект шпион, который будет следить за своим хозяином:
Код
C++ (Qt)
class B
{
public:
   B() {}
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << std::endl;
   }
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << std::endl;
   }
 
   ssc::spy spy;     // Вот этот объект. Его предназначение, следить за своим владельцем.
 
private:
   int _i;
};
 
Но теперь, при создании соединения необходимо также передать ссылку на шпиона (млин, теперь в connect на один аргумент стало больше  Злой ) пример:
Код
C++ (Qt)
int main()
{
   A *a = new A;
   B *b = new B(12);
 
   connect(a->my_signal, b, &B::slot1, b->spy);
   connect(a->my_signal, b, &B::slot2, b->spy);
 
   a->run();
 
   return 0;
}
 

Всё.. Если теперь удалить объект delete b то соединение разорвётся.

Сам шпион представляет из себя следующее:
Код
C++ (Qt)
class spy
{
public:
   spy() : _valid(new bool(true)) {}
   ~spy() { *_valid = false; }
   bool operator()() const { return *_valid; }
   template <class T1, class T2, class T3> friend class manager_connection;
private:
   bool *_valid;
};
 

Хотя на первый взгляд, при уничтожении spy происходит утечка (остаётся висячим _valid) это не совсем так, поскольку его другом является manager_connection и соответственно имеет доступ к его закрытым членам и он ответственен за зачистку указателя _valid.
Теперь, при уничтожении хозяина: delete b, будет также вызван деструктор шпиона, который сделает: *_valid = false;
Но соединение с объектом b создано раньше и владеет указателем на _valid и поэтому всегда знает, что в данный момент происходит с b.
1822  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 20, 2011, 01:06
1) signal
2) smart_ptr

По сигналу: теперь ресивера _обязательно_ заворачивать в smart_ptr?
Теперь обязательно, для того что бы при уничтожении receiver а разрывалось и соответствующее соединение.
Хотя есть и другой вариант как это сделать без использования smart_ptr.

1) signal
2) smart_ptr

smart_ptr просто ужасный:

1. деструктор и operator= должны вызывать общий метод destroy, чтобы их поведение было консистентным (в operator= вы забыли *valid=0, кроме того is_killer обнуляется и объект никто не удалит -- утечка памяти)
Постараюсь объяснить логику этого указателя (для краткости в дальнейшем просто ptr):
ptr может быть либо киллером либо нет. У киллера есть право убить объект. Т.е. право убить объект принадлежит тому, кто первый им завладел. пример:
Код
C++ (Qt)
smart_ptr<B> p1(new B); // p1 - киллер и убъёт объект
smart_ptr<B> p2 = p1;
/* p2 - не имееет права убивать объект, он просто копирует указатель на
на него. флаг _is_killer = false. Сам объект не клонируется.  */

 
Другая ситуация:
Код
C++ (Qt)
smart_ptr<B> p1(new B); // p1 - киллер и убъёт объект
smart_ptr<B> p2(new B); // p2 - тоже киллер!
// Внимание фокус!
p2 = p1; /* Поскольку p2 - киллер он вначале убъёт объект на который ссылается,
затем скопирует указатель на объект на который ссылается p1.
Далее он сбросит флаг _is_killer = false и лишится права удалять объект,
поскольку им уже владел до него p1 и владеет.
Флаг _valid он скопирует также, и соответственно _valid == true, так что пока всё хорошо))  */

// А вот здесь:
 
p1 = p2; /* Ничего не произойдёт, поскольку  operatop=() сначало проверяет не ссылаются
ли они на один и тот же объект. И если да (а в данном случае так и есть)
то return *this и всё.*/

 

Т.е. идея в том, что указателей на объект может быть много, но среди них только у одного есть право его убить. Каждый указатель может изменять данные объекта, но не клонировать его при этом. После того, как киллер  убъёт объект, все остальные смогут узнать об этом, за счёт флага _valid, который будет равен *_valid == false.
Кстати, вот он так и будет висеть и никто его никогда не удалит, но это 1 висячий байт... За то польза))

Цитировать
2. smart_ptr это симметричный объект, не может быть один "киллер", потому что если он погибнет раньше остальных, у других ptr-а не станет. Каждый владелец ptr может оказаться последним, "киллером".

Если киллер умрёт, то он за одно убъёт и сам объект и зделает не валидными оставшиеся ptrЫ. Я такого поведения от него и добивался.

А как Вы видете это всё? Как по Вашему более правильно организовать логику?
Спасибо за обсуждение)  
1823  Qt / Пользовательский интерфейс (GUI) / Re: QColor : Февраль 19, 2011, 23:22
Цитировать
Пробовал так:
const QColor * c = & int QColor::red () const;
const int * c = & int QColor::red () const;
Смеющийся Ну вы и извращенец)) Даже я бы так не смог придумать))
Надо будет запомнить)
1824  Qt / Пользовательский интерфейс (GUI) / Re: QColor : Февраль 19, 2011, 23:14
Цитировать
Пробовал так:
const QColor * c = & int QColor::red () const;
const int * c = & int QColor::red () const;
Смеющийся Ну вы и извращенец)) Даже я бы так не смог придумать))
Надо будет запомнить)


1825  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 19, 2011, 20:13
Дописал)

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

Все классы помещены в пространство имён ssc (от signal slot connection)
Базовые два класса это:
1) signal
2) smart_ptr

Используется так:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
class A
{
public:
   A() {
       std::cout << "A()" << std::endl;
   }
   ~A() {
       std::cout << "~A()" << std::endl;
   }
   ssc::signal<void, std::string> my_signal;
 
   void run() {
       my_signal("Hello Word!");
   }
};
 
class B
{
public:
   B() : _i(0) {
       std::cout << "B()" << std::endl;
   }
   B(int i) : _i(i) {
       std::cout << "B(int  i = " << _i << ")" << std::endl;
   }
   ~B() {
       std::cout << "~B();  i = " << _i << std::endl;
   }
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << "  i = " << _i << std::endl;
   }
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << "  i = " << _i << std::endl;
   }
private:
   int _i;
};
 
int main()
{
   ssc::smart_ptr<A> a = new A;
   // A *a = new A;        можно и так, но придётся удалять руками
 
   //{  если раскомментировать, соединения автоматически разорвуться
 
       ssc::smart_ptr<B> p(new B(12));
   /*  B *b = new B(12)       а вот так можно, но в connect мы его не сможем засунуть
        поскольку connect хочет чтоб b был умным))    
   */

       connect(a->my_signal, p, &B::slot1);
       connect(a->my_signal, p, &B::slot2);
 
   //} см. выше
 
   a->run();
 
   return 0;
}
 


Исходники прилогаются. Прошу потестить, кому не лень. Возможно я где нить накасячил)
Конструктивная критика приветствуется)

 
1826  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 18, 2011, 22:38
Вроде всё работает  Улыбающийся

Теперь всё хорошо и работает так:

Уже симпатично выглядит. А что будет если объект 'b' разрушится (delete например), а потом 'a' испустит сигнал?

В общем самое простое решение я вижу так:
Нужно разорвать соединение, если объект b разрушится.
Это можно сделать, если завернуть объект b в умный указатель, который занулит себя при уничтожении b. А поскольку этот указатель хранится в manager_connection
то перед тем как вызывать operator()() проверять его на валидность.
Как то так.. Сейчас попробую код накатать..   
1827  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 18, 2011, 20:43
Просто в последним варианте, при использовании этого механизма никаких явных template писать уже не нужно, говорю ж всё максимально приближено к Qt варианту сигнал-слот.
Ну а зачем Вы выбрали тему которая уже известна, более того (в каком-то смысле "авторитетна")? Это, на мой взгляд, неразумно/непрактично. Ну посидеть пару вечерков конечно можно - но на этом дело кончится.

Да и что "такого уж хорошего" в ихней схеме слот/сигнал? Везде есть нормальное "sendEvent" (выполнить немедленно) и "postEvent" (засунуть в очередь). Нормальный программист легко этим пользуется, зачем это накручивать в виде MOC компилятора? В результате мы часто видим "месиво из сигналов" вместо нормального, логичного текста.

Ну во-первых лично моё имхо, механизм сигнал-слот - это очень удобная штука. И реализация в Qt это не единственная её реализация. Я не хочу сказать, что в Qt с помощью moc - это круто, напротив, вызов обходится дороже, чем например в схеме сигнал-слот в boost.

Во-вторых я предложил вариант сигнал-слот отличный от реализованного в Qt и отличный от реализации в boost::signal. (как правильно заметил brankovic в boost всё завязано на boost::function)
Это своего рода ещё одна вариация на тему)) И я считаю имеет право быть, хотя бы как объект теоретического исследования)
Короче,
Нет ничего практичнее хорошей теории))
1828  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 18, 2011, 20:03
m_ax, мои замечания - чисто субъективны, я не пытаюсь о чем-то авторитетно судить, делать выводы и.т.п.

Если возникнет вопрос "пользоваться этим или нет", то мой однозначный ответ "нет", и (возможно) я буду здесь совсем не один. Наверняка Вы сделали все правильно, но каждый template требует как-то "настроить мозги". То есть "врубиться" конечно можно, но это обходится недешево, это надо держать в памяти и не забывать. Когда программист сосредоточен на прикладном аспекте - это особенно болезненно. Нет желанной "простоты использования".

Еще раз - это мое субъективное мнение, не более того  Улыбающийся

Отчасти я Вас понимаю, но с другой стороны не писать же с нуля весь инструментарий? Я например, как и многие другие использую Qt и я совсем не парюсь по поводу сколько там у них template или ещё чего. Я в исходники то их от силы раза 3-4 заглядывал)) Мне остаётся только довериться разработчикам)

Или Вы что-то другое имеете ввиду?
Просто в последним варианте, при использовании этого механизма никаких явных template писать уже не нужно, говорю ж всё максимально приближено к Qt варианту сигнал-слот.
Есть, тут правда ещё недопиленные места, но это детали..
 
1829  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 18, 2011, 19:48
Вроде всё работает  Улыбающийся

Теперь всё хорошо и работает так:

Уже симпатично выглядит. А что будет если объект 'b' разрушится (delete например), а потом 'a' испустит сигнал?

Известно что: грохинг программы  Смеющийся

Я как раз курю на эту тему)) Если есть предложения буду рад выслушать.
1830  Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот : Февраль 18, 2011, 19:28
Вроде всё работает  Улыбающийся

Теперь всё хорошо и работает так:

main.cpp
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
class A
{
public:
   A() {}
   signal<void, std::string> my_signal;
 
   void run() {
       my_signal("Hello Word!");
   }
};
 
class B
{
public:
   B() {}
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << std::endl;
   }
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << std::endl;
   }
};
 
int main()
{
 
   A a;
   B b;
 
   connect(&b, &B::slot1, &a.my_signal);
   connect(&b, &B::slot2, &a.my_signal);
 
   a.run();
 
   return 0;
}
 
Теперь всё как в Qt и только с использованием шаблонов  Крутой

Функция connect создаёт соединение между слотом объекта класса b и сигналом объекта a.
Сам сигнал представляет из седя шаблонный класс
template <class T_return, class T_arg> class signal
где
T_return - тип возвращаемого аргумента
T_arg - тип передаваемого аргумента

Если нужно чтобы ваш клас умел испускать сигналы необходимо просто включить класс сигнала в определение класса, как в примере:
Код
C++ (Qt)
class A
{
public:
   A() {}
/*
Объявляем сигнал, который будет соеденён с функцией, которая возвращает void
и принимает один аргумент std::string
*/

   signal<void, std::string> my_signal;  
 
/*
В той функции, где необходимо вызвать сигнал, просто вызываем сигнал как обычную функцию  
*/
                                   
   void run() {
       my_signal("Hello Word!");
   }
};
 


Сама реализация механизма сигнал-слот:
Код
C++ (Qt)
#ifndef SIGNAL_SLOT_H
#define SIGNAL_SLOT_H
 
#include <list>
 
template <class T_return, class T_arg>
class base_signal
{
public:
   base_signal() {}
   virtual ~base_signal() {}
   virtual T_return operator() (const T_arg &) = 0;
};
 
template <class T_receiver, class T_return, class T_arg>
class manager_connection;
 
template <class T_return, class T_arg>
class signal
{
public:
   signal() {}
   ~signal() {
       for (_iterator it = _list.begin(); it != _list.end(); it++) {
           delete *it;
       }
       _list.clear();
   }
 
   T_return operator() (const T_arg &arg) {
       for (_iterator it = _list.begin(); it != _list.end(); it++) {
           (*it)->operator()(arg);
       }
   }
 
   template <class T1, class T2, class T3> friend class manager_connection;
 
private:
   std::list<base_signal<T_return, T_arg>* > _list;
   typedef typename std::list<base_signal<T_return, T_arg>* >::iterator _iterator;
 
   void connect(base_signal<T_return, T_arg> *_signal) {
       _list.push_back(_signal);
   }
};
 
template <class T_receiver, class T_return, class T_arg>
class manager_connection : public base_signal<T_return, T_arg>
{
public:
   typedef T_return (T_receiver::*function_type_1)(T_arg);
   typedef T_return (T_receiver::*function_type_2)(const T_arg &);
   typedef T_return (T_receiver::*function_type_3)(T_arg) const;
   typedef T_return (T_receiver::*function_type_4)(const T_arg &) const;
 
   manager_connection(T_receiver *obj, function_type_1 slot, signal<T_return, T_arg> *s) {
       _receiver = obj;
       _slot_1 = slot;
       _index = 1;
       s->connect(this);
   }
 
   manager_connection(T_receiver *obj, function_type_2 slot, signal<T_return, T_arg> *s) {
       _receiver = obj;
       _slot_2 = slot;
       _index = 2;
       s->connect(this);
   }
 
   manager_connection(T_receiver *obj, function_type_3 slot, signal<T_return, T_arg> *s) {
       _receiver = obj;
       _slot_3 = slot;
       _index = 3;
       s->connect(this);
   }
 
   manager_connection(T_receiver *obj, function_type_4 slot, signal<T_return, T_arg> *s) {
       _receiver = obj;
       _slot_4 = slot;
       _index = 4;
       s->connect(this);
   }
 
   ~manager_connection() {
   }
 
   T_return operator()(const T_arg &arg) {
       if (_index == 1)
           return (_receiver->*_slot_1)(arg);
       if (_index == 2)
           return (_receiver->*_slot_2)(arg);
       if (_index == 3)
           return (_receiver->*_slot_3)(arg);
       if (_index == 4)
           return (_receiver->*_slot_4)(arg);
 
       return T_return();
   }
 
private:
   T_receiver *_receiver;
   function_type_1 _slot_1;
   function_type_2 _slot_2;
   function_type_3 _slot_3;
   function_type_4 _slot_4;
   int _index;
   manager_connection() : _receiver(0), _index(0) {}
   manager_connection(const manager_connection &) {}
 
};
 
 
template <class T_receiver, class T_return, class T_arg>
void connect(T_receiver *obj, T_return (T_receiver::*slot)(T_arg), signal<T_return, T_arg> *s) {
   new manager_connection<T_receiver, T_return, T_arg>(obj, slot, s);
}
 
template <class T_receiver, class T_return, class T_arg>
void connect(T_receiver *obj, T_return (T_receiver::*slot)(const T_arg &), signal<T_return, T_arg> *s) {
   new manager_connection<T_receiver, T_return, T_arg>(obj, slot, s);
}
 
template <class T_receiver, class T_return, class T_arg>
void connect(T_receiver *obj, T_return (T_receiver::*slot)(T_arg) const, signal<T_return, T_arg> *s) {
   new manager_connection<T_receiver, T_return, T_arg>(obj, slot, s);
}
 
template <class T_receiver, class T_return, class T_arg>
void connect(T_receiver *obj, T_return (T_receiver::*slot)(const T_arg &) const, signal<T_return, T_arg> *s) {
   new manager_connection<T_receiver, T_return, T_arg>(obj, slot, s);
}
 
#endif // SIGNAL_SLOT_H
 

Архив с проектом прикреплён.
Страниц: 1 ... 120 121 [122] 123 124 ... 140

Страница сгенерирована за 0.597 секунд. Запросов: 24.