// счётчик времениtypedef void const* event_t;
int next_tick(event_t event) // event - произвольный идентификатор события. Подряд идущие события сливаются, чтобы уменьшить риск перемотки
{
static event_t last_event = NULL;
static int last_tick = 0;
if(last_event != event) { last_event = event; ++last_tick; }
return last_tick;
}
class C1
{
public:
int tick;
void foo() { tick=next_tick(this); ...... }
};
class C2
{
C1* link;
int tick;
void foo()
{
int diff = this->tick - link->tick;
if(diff < 0)
..... // были вызовы link->foo() после последнего this->foo()
tick=next_tick(this);
.....
}
};
Можно и более изощрённую логику придумать. Скажем, очередь...
struct history_t
{
typedef void const* event_t;
std::vector<event_t> frame; // окно истории (последовательность событий в порядке их возникновения)void add(event_t event) // встаём в хвост очереди (естественно, выбывая из середины)
{
frame.erase(std::find(frame.begin(),frame.end(),event));
frame.push_back(event);
}
int find(event_t event) const// положение в очереди (от хвоста); 0 означает отсутствие
{
return std::distance(std::find(frame.begin(),frame.end(),event),frame.end());
}
} history;
class C1
{
void foo() { history.add(this); ..... }
};
class C2
{
C1* link;
void foo()
{
int linkpos = history.find(link), thispos = history.find(this);
// (0..thispos) - отрезок между настоящим моментом и последним вызовом this->foo()if(linkpos>0 && linkpos<thispos)
... // где-то между ними был совершён link->foo()if(thispos==0 && linkpos!=0)
... // this->foo() вызывается в первый раз, а link->foo() уже былif(linkpos==0)
... // link->foo() вообще не вызывался
.......
history.add(this);
}
};
Если объектов много, то вместо вектора можно придумать что-нибудь побыстрее. Начиная от интрузивного списка, и кончая boost::multi_index.
Ну очевидно, что в системе кто-то должен наблюдать за тем, кто после кого запускается. Можно отдельный класс сделать, в котором каждый экземпляр будет регистрироваться, можно его в C1 запихнуть. Например как-то так:
проблема в том, чтобы при каждом вызове c2_x.foo() мы как-то должны знать, что уже вызывалась c1.foo().
Можно добавить в C1 и C2 флаг, который бы менялся в c1.foo() и сигнализировал об ее запуске, а в c2_x.foo() шло бы сравнение старого флага, хранящегося в c2_x и флага из Ref. Но что если мы запустим c1.foo() столько раз, чтобы флаг вернулся в исходное состояние, и c2_x.foo() обломится (если использовать в качестве флага перечислимый тип). Кто што может предложить? Спась.
Здравствуйте, piAnd, Вы писали:
A>Привет всем! Подскажите хотяб идею для решения вот такой проблемы.
A>
A>//определение
A>class C1{
A>public:
A> void foo(){/*...*/}
A>};
A>//и
A>template <typename T>
A>class C2{
A>public:
A> C2(T &Src):Ref(Src){}//в Ref храним ссылку на заданный объект
A> void foo(){/*...*/}
A> T &Ref;
A>};
A>//в главном cpp:
A>C1 c1;
A>C2<C1> c2_1(с1);
A>C2<C1> c2_2(с1);
A>
A>проблема в том, чтобы при каждом вызове c2_x.foo() мы как-то должны знать, что уже вызывалась c1.foo(). A>Можно добавить в C1 и C2 флаг, который бы менялся в c1.foo() и сигнализировал об ее запуске, а в c2_x.foo() шло бы сравнение старого флага, хранящегося в c2_x и флага из Ref. Но что если мы запустим c1.foo() столько раз, чтобы флаг вернулся в исходное состояние, и c2_x.foo() обломится (если использовать в качестве флага перечислимый тип). Кто што может предложить? Спась.
А чем не устраивает вызвать foo в C2::foo ?
Защита от повторного выбора делается элементарно:
void C1::foo()
{
static bool flag;
if(!flag)
{
flag = true;
// делаем что надо
}
}
Здравствуйте, _nn_, Вы писали:
__>А чем не устраивает вызвать foo в C2::foo ?
дык C1::foo и C2::foo совершенно разные __>Защита от повторного выбора делается элементарно: __>
__>void C1::foo()
__>{
__> static bool flag;
__> if(!flag)
__> {
__> flag = true;
__> // делаем что надо
__> }
__>}
__>
в этом и вопрос, если непредупредив C2::foo, вызываю C1::foo 2 раза и возвращаюсь на круги своя, а это . А предупредить C2::foo из C1::foo никак нельзя, ибо C2::foo вообще может не быть, классы то совершенно несвязаны иерархически, и никаких предположений об C2 в C1 не делается. В этом трабл.
А вообще я ошибочно поставил вопрос.
Каждый из экземпляров c2_x может быть создан в любой момент, поэтому один булевый флаг на всех и не катит. В том числе не катит и целочисленный, по причине ограниченности его диапазона. + C1 ничего не знает об C2. Поэтому как-то должен сам предоставлять некий метод или что-то еще...
Здравствуйте, piAnd, Вы писали:
A>Здравствуйте, _nn_, Вы писали:
A>А вообще я ошибочно поставил вопрос. A>Каждый из экземпляров c2_x может быть создан в любой момент, поэтому один булевый флаг на всех и не катит. В том числе не катит и целочисленный, по причине ограниченности его диапазона. + C1 ничего не знает об C2. Поэтому как-то должен сам предоставлять некий метод или что-то еще...
Здравствуйте, Garrett, Вы писали: G>Ну тут уже товарищ Кодт успел ответить, пока я пытался с условиями задачи разобраться и вообще от других дел отвязаться
всем спасибо за решения!
К>>class C2
К>>{
К>> C1* link;
К>> int tick;
К>> void foo()
К>> {
К>> int diff = this->tick - link->tick;
К>> if(diff < 0)
К>> ..... // были вызовы link->foo() после последнего this->foo()
К>> tick=next_tick(this);//кстати тут можно счетчик не накручивать,
К>> //а просто поменять last_event => не выйдем
К>> //за дозволеный диапазон int
К>> .....
К>> }
К>>};
Мне, на первый взгляд, кажется, что всё-таки надо накрутить счётчик. Хотя... можно и не делать этого.
Если целочисленное переполнение не приводит к аппаратным исключениям (а я надеюсь, что это так — иначе добрая половина сишных программ на этой архитектуре перестанет работать), то код устойчив к абсолютной перекрутке (переходу last_tick через INT_MAX).
Главное, чтобы между событиями someC1.foo() и someC2.foo() было не более INT_MAX разных событий. Именно поэтому сравнивается не this->tick с link->tick, а их разность с нулём.
Здравствуйте, Кодт, Вы писали:
К>Если целочисленное переполнение не приводит к аппаратным исключениям (а я надеюсь, что это так — иначе добрая половина сишных программ на этой архитектуре перестанет работать), то код устойчив к абсолютной перекрутке (переходу last_tick через INT_MAX). К>Главное, чтобы между событиями someC1.foo() и someC2.foo() было не более INT_MAX разных событий. Именно поэтому сравнивается не this->tick с link->tick, а их разность с нулём.
Подробно протестил варианты этой техники (где есть какой-либо перечислимый флаг, в данном случае tick). Вывод — каким бы ни был метод с использованием так или иначе инкрементального флага, будет существовать "краевой вариант обмана", т.е. будет существовать такой вариант манипуляций с вызовами, при котором одна из C2::foo будет обманута. Вобщем лучше тогда переделать сами классы, чем мутить доп. контейнеры...