如何在分配时实现自动更新

时间:2011-06-27 06:00:17

标签: c++ automation

请考虑以下代码:

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()吗?

[编辑]
请注意,创建的更新函数也分配给函数指针 第三方API,因此它可以自己进行内部更新。因此,使更新函数非全局化是不可能的,因此当前更新函数是全局的 [编辑]
我还重写了我的例子,以便更加理解和纠正我正在使用的实际API

e.g

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

4 个答案:

答案 0 :(得分:4)

是的,你可以。为此使用类方法。将类中的静态方法作为更新函数传递给第三方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 ++中的类。稍后您只能学到一些细微差别。

答案 1 :(得分:2)

很难为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();
}

答案 2 :(得分:1)

您需要使用Observer设计模式或其略微变体。 请参阅此示例here

答案 3 :(得分:1)

通常的方法是将foobar转换为重载赋值运算符的某种类型:

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.