Turi Create  4.0
Advanced Object Creation

(If you have not seen the CPPIPC Basic Concepts section, you should. we will continue extending the basic_counter object defined in the previous section.)

Now, while the CPPIPC system is kind of nice for basic stuff, what should be done in situations when I need to define a function which takes another remote object as input (For instance, say I want to add two basic counters together)? Or how do I create functions which return new remote objects ( for instance, if I want to "clone" a counter) ?

To handle this case, we perform some magic which are explained in in the Technical Details page. But in short, you simply pass and return pointers to objects.

For instance, to implement a "clone" function, we simply extend the interface with a clone function that returns a new base object (it must be a base, since to the server, it is an implementation object, and to the client, it is a proxy object)

GENERATE_INTERFACE_AND_PROXY(basic_counter_base, basic_counter_proxy,
(int, add, (int))
(int, add_multiple, (int)(int))
(int, get_val, )
(basic_counter_base*, clone, )
)

On the server-side, we implement the clone() function. This just creates a new basic_counter object, and returns it. The returned object will automatically be registered and managed by the comm_server.

basic_counter_base* basic_counter::clone() {
basic_counter* new_counter = new basic_counter;
new_counter->value = value;
return new_counter;
}

Now, to use this function on the client side,

...
// prints the counter value
std::cout << "Counter Value: " << proxy.get_val() << "\n";
// upcast it to proxy. Not strictly necessary
// we can also just leave it as a pointer to base
//
// i.e.
// basic_counter_base* new_counter = proxy.clone();
basic_counter_proxy* new_counter =
dynamic_cast<basic_counter_proxy*>(proxy.clone());
// prints the new counter value
std::cout << "New Counter Value: " << new_counter->get_val() << "\n";
// its a pointer, so we must explicitly delete it
// On deletion, it will delete the matching counter object on the server side
delete new_counter;

To take remote objects as arguments is similar. Here, we add a new "add_counter" function which adds the value of another counter to the current counter. Once again, it must take a pointer to base as the argument.

GENERATE_INTERFACE_AND_PROXY(basic_counter_base, basic_counter_proxy,
(int, add, (int))
(int, add_multiple, (int)(int))
(int, get_val, )
(basic_counter_base*, clone, )
(void, add_counter, (basic_counter_base*))
)

While on the client side, the function is called with a pointer to a proxy object, it is resurrected as a pointer to an implementation object on the server side.

void basic_counter::add_counter(basic_counter_base* other) {
// upcast to the basic_counter.
basic_counter* other_derived = dynamic_cast<basic_counter*>(other);
value += other_derived->value;
// once again, in this case this is not strictly necessary,
// we can get by with keeping it in the base class and just write
//
// value += other->get_val();
}

Now, to use this function on the client side,

basic_counter_proxy counter1(client);
basic_counter_proxy counter2(client);
... do stuff ..
counter1.add_counter(&counter2);