Russian Qt Forum

Программирование => С/C++ => Тема начата: deaks от Февраля 16, 2011, 12:34



Название: Передача данных
Отправлено: deaks от Февраля 16, 2011, 12:34
Добрый день,

посоветуйте, как лучше всего в данном случае организовать передачу данных между классом MissileDynamic и MissileACS - ситуация, когда один класс использует переменную, а потом второй хочет ее так же видеть
По хорошему они не должны знать друг о друге ничего.

Есть объект, который в себя включает Динамику(Dynamic) и Управление(Control).

Соответственно система включает в себя еще больше компонентов, показана лишь часть.

(http://s42.radikal.ru/i098/1102/2d/35f007d68365.jpg)



Название: Re: Передача данных
Отправлено: santaclaus от Февраля 16, 2011, 13:16
ну в том месте где они оба используются, соединить их сигналом и слотом, что бы один класс делал
Код:
emit mySignal("MyParametr");
а второй соответственно
Код:
connect(sender, SIGNAL(mySignal(QString)), reciver, SLOT(slotSetParam(const QString &)));


Название: Re: Передача данных
Отправлено: Пантер от Февраля 16, 2011, 13:18
santaclaus, с чего ты взял, что тут есть сигналы/слоты?


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 13:20
ну

во-первых мне надо в рамках чистого c++, без qt
во-вторых здесь опять же нет связи через Object

я реализовывал все это дело структурами, то есть все нужные параметры определенного класса упаковывал в структуру и потом возвращал указатель на нее через интерфейс. но это дело не понравилось, так как в классах появились наследуемые структуры


Название: Re: Передача данных
Отправлено: Sergey B. от Февраля 16, 2011, 13:45
Посмотрите на libsig++ как там это сделано. Оно используется в Gtkmm. Чистый С++.


Название: Re: Передача данных
Отправлено: Fat-Zer от Февраля 16, 2011, 13:47
глупый вопрос, но пунктирная стрелочка в терминах C++ что означает? виртуальное наследование?


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 14:01
мой вопрос глупый? Оо

пунктирная стрелочка - интерфейс


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 14:03
Посмотрите на libsig++ как там это сделано. Оно используется в Gtkmm. Чистый С++.

а если кроме сигнал-слотов? какие еще возможны варианты. задача-то вполне ординарная


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 14:06
так как класс Object включает интерфейсы IControl, IDynamic, то как через эти интерфейсы лучше всего возвращать требуемые значения соответствующих классов потомков


Название: Re: Передача данных
Отправлено: Fat-Zer от Февраля 16, 2011, 14:16
мой вопрос глупый? Оо
пунктирная стрелочка - интерфейс
Нет, это я про свои вопросы... а в цпп это ведь через обычное наследование реализуется...


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 14:25
 :)
ага это и есть обычное наследование)
а такая стрелка - различает обычные классы-потомки и классы-интерфейсы)


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 14:55
товарищи, посоветуйте какой-нибудь изящный вариант решения)


Название: Re: Передача данных
Отправлено: developer от Февраля 16, 2011, 15:38
Не знаю поможет ли мой ответ. Но возможно должен хотя бы на что-то направить.

Припустим ты создаеш два класса А и Б. Класс А должен быть уведомлен если класс Б изменил свою переменную.

А что если создать класс С и передать как переменную в классы А и Б.

Код:

class C:
{
    private:
       Container<object*> container;
   
    public:
        void update() { /*pseudocod*/ foreach(Container<object*> o, container) { o->changeSomething(/*set of params*/); } };
        void addClass(object* obj) { container.append(obj); }
}

//
С* с = new C();
A* a = new A(c);
B* b = new B(c);

//потом класс С сделать контейнером для классов Б и А.
c->addClass(a);
c->addClass(b);

// тепер когда в классе А что-то случиться вызвать функцию update() класса С
..........
void ClassA_or_B_function()
{
       //ссылку на с мы уже више настроили.
       c->update();
}
..........









Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 16:19
похожий вариант в принципе рассматривал,

но хочется чтобы за все манипуляции отвечал Object через интерфейсы


Название: Re: Передача данных
Отправлено: twp от Февраля 16, 2011, 17:10
не уверен, но вероятно здесь подойдет паттерн проектирования Посредник (Медиатор)


Название: Re: Передача данных
Отправлено: m_ax от Февраля 16, 2011, 17:11
libsig++ Хороший вариант

Если нехочется прикручивать всю библиотеку то можно сделать так:

Код
C++ (Qt)
#include <iostream>
 
using namespace std;
 
 
template <class T, typename U>
class Signal
{
public:
   Signal() {
       _obj = 0;
       _slot = 0;
   }
   void operator()(const U& val) {
       if (_obj) {
           (_obj->*_slot)(val);
       }
   }
   void connect(T *obj, void (T::*slot)(const U &)) {
       _obj = obj;
       _slot = slot;
   }
 
private:
   T *_obj;
   void (T::*_slot)(const U &);
};
 
 
template<class T>
class Sender
{
public:
   Sender(){}
   Signal<T, int> signal;
   void run() {
       signal(123);
   }
};
 
class Receiver
{
public:
   Receiver() {}
   void slot(const int &x) {
       cout << x << endl;
   }
};
 
int main()
{
   Sender<Receiver> sender;
   Receiver receiver;
   sender.signal.connect(&receiver, &Receiver::slot);
 
   sender.run();
 
   return 0;
}
 
 
Это фактически сильно упрощённая схема сигнал-слот, реализованая в libsig++


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 17:45
да не, я же говорю все планирую делать через Object. У его интерфейсов можно вызывать функции getData, - что-то типа того, которые возвращают данные объекта в зависимости от параметра, который указывает на этот объект.
У меня сейчас именно так и реализовано, но при этом все данные классов зашиты в структуры, которые друг от друга наследуются. Но тут возникает неприятный момент - в самом классе, в котором описана структура переменных, приходится ведь работать через данную структуру(ахинея какая-та получается), напрямую в переменную уже не запишешь. Код состоит сплошь из имен структуры. В общем все это как-то криво выглядит  - примерно так:
Код:
	airData._Va = airData._V = airData.V.Length();

if(airData._Va < 0.5)
airData._Va = 0.5;

airData.betaR = asin(airData.V.z/ airData._Va);

if(fabs(airData.V.y) < 0.01 && fabs(airData.V.x) < 0.01)
airData.alphaR = 0.;
else
airData.alphaR = atan2(airData.-V.y, airData.V.x);

airData.alpha = airData.alphaR * M_C57;
airData.beta = airData.betaR * M_C57;


Название: Re: Передача данных
Отправлено: ruzik от Февраля 16, 2011, 18:32
Может я не правильно что-то понял, но почему бы не сделать один абстрактный класс, со статической функцией, а классы А и Б просто унаследовать от этого класса, ну а когда в классе А изменяется переменная, вызывать эту функцию


Название: Re: Передача данных
Отправлено: m_ax от Февраля 16, 2011, 18:50
Вся проблема, как я понял, в синтаксическом удобстве. Нет?


Название: Re: Передача данных
Отправлено: ruzik от Февраля 16, 2011, 20:16
Вся проблема, как я понял, в синтаксическом удобстве. Нет?
Я думаю под "изящным вариантом" автор подразумевает наиболее быстрый и легкий способ, так что можно сказать-да, в синтаксическом удобстве


Название: Re: Передача данных
Отправлено: deaks от Февраля 16, 2011, 21:36
именно так, товарищи) синтаксическое удобство


Название: Re: Передача данных
Отправлено: ruzik от Февраля 16, 2011, 21:47
Ну тогда я думаю что это самое простое и быстрое решение
Код:
почему бы не сделать один абстрактный класс, со статической функцией, а классы А и Б просто унаследовать от этого класса, ну а когда в классе А изменяется переменная, вызывать эту функцию


Название: Re: Передача данных
Отправлено: m_ax от Февраля 16, 2011, 21:56
Цитировать
Может я не правильно что-то понял, но почему бы не сделать один абстрактный класс, со статической функцией, а классы А и Б просто унаследовать от этого класса, ну а когда в классе А изменяется переменная, вызывать эту функцию
Я что то не улавливаю причинно-следственную связь..  ??? Видимо уже не соображаю под вечер))


Название: Re: Передача данных
Отправлено: ruzik от Февраля 16, 2011, 22:08
Постараюсь объяснить как смогу:
Код:
class A
{
public:
static void qwerty();
vitrual void doIt();
}
void A::qwerty()
{
void doIt();
}
class B : public A
{
private:
 int a;
public:
int set_a(int ab);
}
int B::set_a(int ab)
{
a=ab;
qwerty();
}
class C : public A
{
void doIt();
}
void C::doIt()
{
IamDoIt(); //это то что надо сделать
}
Вроде должно работать, хотя и не факт  ;D
класс А-это "папа"
B и С -наследуемые


Название: Re: Передача данных
Отправлено: m_ax от Февраля 16, 2011, 22:21
Боюсь это работать не будет.
Статические функции класса могут юзать только статические переменные и статические же функции.


Название: Re: Передача данных
Отправлено: ruzik от Февраля 16, 2011, 22:26
Не знал :(


Название: Re: Передача данных
Отправлено: trot от Февраля 16, 2011, 23:01
Типичный случай патерна "Подписчик-издатель".
Примерно следующая схема.
Объекта класса А изменяет какую-то переменную, после этого он посылает сигнал оповещения, о том что значение переменной изменилось. Те объекты, которые следят за изменением этой переменной должны подписаться на получение оповещение.
Я реализовал у себя следующим образом.
1. Создал класс С (по сути это интерфейс), который будет заниматься оповещением своих подписчиков.
Код:
class С 
{

public:
С();
~Сe();

void addObserver(Observer *); //добавляет слушателя
void notifyObservers(Observer * = 0); //оповещает слушателей, параметром является тот объект, который вызвал оповещение            //этот параметр нужен для того, чтобы не запускать update самого себя
private:
QList<Observer *> * m_listObserver; //хранилище слушателей

};
void Observable::addObserver(Observer * o){
if(!m_listObserver->contains(o))
m_listObserver->append(o);
}

void Observable::notifyObservers(Observer * o){
for(int i=0; i<m_listObserver->count(); i++){
if(o!=m_listObserver->at(i))
m_listObserver->at(i)->update(this);
}
}
2. Создаем класс А (тот класс, который меняет переменную) наследуемый от класса (интерфейса) С.
3. Создаем интерфейс D с виртуальным методом update.
4. Создаем класс В (тот класс, который следит за изменением переменной) наследуемый от интерфейса В.
5. Далее связываем издателя с подписчиком, т.е. вызываем метод addObserver с параметром интерфейса С.
6. Когда объекта класса А (издатель) меняет переменную, то он выполняет метод notifyObservers, который переберает всех подписчиков и выполняет их интерфейсный метод update ().
Примерно так. Это я подсмотрел, как данный патерн реализован в стандартной библиотеки java.