Как именно будет реализовано автоматическое обновление при назначении - PullRequest
1 голос
/ 27 июня 2011

Рассмотрим следующий код:

struct data
{
    int foo;
    int bar;
};

data a;
a.foo = 200;
a.bar = 300;

static void update(data* a, int rspec)
{
  if (!rspec) //my data management
  {
      3rdPartyApi->CreateStream();
      3rdPartyApi->PushData(a->foo);
      3rdPartyApi->PushData(a->bar);
      3rdPartyApi->CloseStream();
  }
  else // internal data management
  {
      3rdPartyApi->CreateStream();
      3rdPartyApi->PushData(3rdPartyApi->BufferQueue);
      3rdPartyApi->CloseStream();
  }
  3rdPartyApi->PushStream(3rdPartyApi->GetLastStreamBuffer().POD());
}

Допустим, я меняю значение a.foo или a.bar, и мне требуется вызвать Update там после назначения. Можно ли это сделать, не вызывая Update () для каждого изменения вручную?

[EDIT]
Обратите внимание, что созданная функция обновления также назначается указателю функции для сторонний API, так что он может делать свое собственное внутреннее обновление. Поэтому сделать функцию обновления неглобальной невозможно, поэтому текущая функция обновления является глобальной.
[EDIT]
Я также переписал мой пример, чтобы он был более понятным и верным для реального API, который я использую

1011 * например *

3rdPartyApi->StreamUpdate((void (*)(void*, int))update);

Ответы [ 4 ]

4 голосов
/ 27 июня 2011

Да, вы можете. Используйте методы класса для этого. Передайте статический метод из вашего класса в сторонний API в качестве функции обновления.

class data
{
public:
    void set_foo(int new_foo);
    void set_bar(int new_bar);

    int get_foo() const;
    int get_bar() const;

    // This is the update signature which the 3rd party API can accept.
    static void update(void* ptr, int rspec);

private:
    // These are private so we can control their access.
    int foo;
    int bar;
};

void data::set_foo(int new_foo)
{
    foo = new_foo;
    // 'this' is a special pointer for current data object.
    update(this);
}

void data::set_bar(int new_bar)
{
    bar = new_bar;
    update(this);
}

int data::get_foo() const
{
    return foo;
}

int data::get_bar() const
{
    return bar;
}

// This is needed if the 3rd party API can only call C bindings.
// If it's a C++ API this is not needed.
extern "C" {

void data::update(void* ptr, int rspec)
{
    if (!rspec) //my data management
    {
        // You have to cast to data* from void*.
        data* data_ptr = reinterpret_cast<data*>(ptr);

        3rdPartyApi->CreateStream();
        3rdPartyApi->PushData(data_ptr->foo);
        3rdPartyApi->PushData(data_ptr->bar);
        3rdPartyApi->CloseStream();
    }
    else // internal data management
    {
        3rdPartyApi->CreateStream();
        3rdPartyApi->PushData(3rdPartyApi->BufferQueue);
        3rdPartyApi->CloseStream();
    }
    3rdPartyApi->PushStream(3rdPartyApi->GetLastStreamBuffer().POD());
}

} /* extern "C" */

Тогда:

3rdPartyApi->StreamUpdate(&data::update);
data a;
a.set_foo(200);
a.set_bar(300);

Обратите внимание, что использование struct вместо class здесь одинаково хорошо. Но соглашение состоит в том, чтобы использовать классы в C ++. Есть только небольшая разница, которую вы можете узнать позже.

2 голосов
/ 27 июня 2011

Трудно написать код для foo, bar и data, поэтому давайте сделаем его более конкретным:

class point
{
public:
    int x_coord() const;
    int y_coord() const;

    void move_to(int new_x, int new_y);

private:
    void update_3rd_party();

    int   x;
    int   y;
};

void point::move_to(int new_x, int new_y)
{
    x = new_x;
    y = new_y;
    // whatever else needs to be done

    update_3rd_party();
}
1 голос
/ 27 июня 2011

Обычным способом было бы превратить foo и bar в некоторый тип, который перегружает оператор присваивания:

class updated_int { 
    int value;
public:
    updated_int(int init = 0) : value(init) {}

    updated_int &operator=(int new_val) { 
        value = new_val;
        update();
        return *this;
    }

    // You might want to declare this private and not implement it.
    updated_int &operator=(updated_int const &r) { 
        value = r.value;
        update();
        return *this;
    }
    operator int() { return value; }
};

struct data { 
    updated_int foo;
    updated_int bar;
}

data a;
a.foo = 1; // operator= will call update() automatically.
1 голос
/ 27 июня 2011

Вам необходимо использовать Observer шаблон проектирования или его небольшой вариант. Смотрите этот пример здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...