1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 92 pot

6 56 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Nội dung

class were trivial, and user code wasn't affected at all. As shown here, introducing Boost.Function into an existing design is typically straightforward. Functions That Are Class Members Boost.Function does not support argument binding, which would be needed to make each invocation of a function invoke a member function on the same class instance. Fortunately, it is possible to directly call member functions if the class instance is passed to the function. The signature of the function needs to include the type of the class, as well as the signature of the member function. In other words, the class instance is passed explicitly as what would normally be the implicit first parameter, this. The result is a function object that invokes a member function on the supplied object. Consider the following class: class some_class { public: void do_stuff(int i) const { std::cout << "OK. Stuff is done. " << i << '\n'; } }; The member function do_stuff is to be called from within an instance of boost::function. To do this, we need the function to accept an instance of some_class, and have the rest of the signature be a void return and an int argument. We have three choices when it comes to deciding how the instance of some_class should be passed to the function: by value, by reference, or by address. To pass by value, here's how the code would look. [4] [4] There are seldom good reasons for passing the object parameter by value. boost::function<void(some_class,int)> f; Note that the return type still comes first, followed by the class where the member function is a member, and finally the arguments to the member function. Think of it as passing this to the function, which is implicitly the case when calling non- static member functions on an instance of a class. To configure the function f with the member function do_stuff, and then invoke the function, we do this: f=&some_class::do_stuff; f(some_class(),2); When passing by reference, we change the signature of the function, and pass an instance of some_class. boost::function<void(some_class&,int)> f; f=&some_class::do_stuff; some_class s; f(s,1); Finally, to pass a pointer [5] to some_class, this is how we'd write the code: [5] Both raw pointers and smart pointers will do. boost::function<void(some_class*,int)> f; f=&some_class::do_stuff; some_class s; f(&s,3); So, all the likely variants for passing instances of the "virtual this" are provided by the library. Of course, there is a limitation to this technique: You have to pass the class instance explicitly; and ideally, you'd want the instance to be bound in the function object instead. At first glance, that seems to be a disadvantage of Boost.Function, but there are other libraries that support binding arguments, such as Boost.Bind and Boost.Lambda. We will examine the added value that a collaboration with such libraries brings to Boost.Function later in this chapter. Stateful Function Objects We have already seen that it is possible to add state to callback functions, because of the support for function objects. Consider a class, keeping_state, which is a function object with state. Instances of keeping_state remember a total, which is increased each time the function call operator is invoked. Now, when using an instance of this class with two instances of boost::function, the results may be somewhat surprising. #include <iostream> #include "boost/function.hpp" class keeping_state { int total_; public: keeping_state():total_(0) {} int operator()(int i) { total_+=i; return total_; } int total() const { return total_; } }; int main() { keeping_state ks; boost::function<int(int)> f1; f1=ks; boost::function<int(int)> f2; f2=ks; std::cout << "The current total is " << f1(10) << '\n'; std::cout << "The current total is " << f2(10) << '\n'; std::cout << "After adding 10 two times, the total is " << ks.total() << '\n'; } When writing, and subsequently running, this program, the programmer probably expects that the total stored in ks is 20, but it's not; in fact, it's 0. This is the output when running the program. The current total is 10 The current total is 10 After adding 10 two times, the total is 0 The reason is that each instance of function (f1 and f2) contains a copy of ks, and each of those instances winds up with a total value of 10, but ks is unchanged. This may or may not be what is intended, but it is important to remember that the default behavior of boost::function is to copy the function object that it is to invoke. If that produces incorrect semantics, or if the copying of some function objects is too expensive, you must wrap the function objects in boost::reference_wrapper so that boost::function's copy will be a copy of a boost::reference_wrapper, which just holds a reference to the original function object. You rarely use boost::reference_wrapper directly, but rather you use two helper functions, ref and cref. Those functions return a reference_wrapper that holds a reference or const reference to the parameterizing type. To get the semantics that we want in this case, using the same instance of keeping_state, we need to change the code, like this: int main() { keeping_state ks; boost::function<int(int)> f1; f1=boost::ref(ks); boost::function<int(int)> f2; f2=boost::ref(ks); std::cout << "The current total is " << f1(10) << '\n'; std::cout << "The current total is " << f2(10) << '\n'; std::cout << "After adding 10 two times, the total is " << ks.total() << '\n'; } This usage of boost::ref informs boost::function that we want to store a reference to the function object, not a copy. Running this program produces the following output: The current total is 10 The current total is 20 After adding 10 two times, the total is 20 This is exactly the behavior that we needed in this case. The difference between using boost::ref and boost::cref is exactly the same as the difference between references and references to constyou can only call constant member functions for the latter. The following example uses a function object called something_else, which has a function call operator that is const. class something_else { public: void operator()() const { std::cout << "This works with boost::cref\n"; } }; With this function object, we could use either boost::ref or boost::cref. something_else s; boost::function0<void> f1; f1=boost::ref(s); f1(); boost::function0<void> f2; f2=boost::cref(s); f2(); If we change the implementation of something_else and make the function non-const, only boost::ref will work, whereas boost::cref would produce an error at compile time. class something_else { public: void operator()() { std::cout << "This works only with boost::ref, or copies\n"; } }; something_else s; boost::function0<void> f1; f1=boost::ref(s); // This still works f1(); boost::function0<void> f2; f2=boost::cref(s); // This doesn't work; // the function call operator is not const f2(); When a function contains a function object wrapped by boost::reference_wrapper, copy construction and assignment replicates the referencethat is, the copy of the function references the original function object. int main() { keeping_state ks; boost::function<int,int> f1; f1=boost::ref(ks); boost::function<int,int> f2(f1); boost::function<short,short> f3; f3=f1; std::cout << "The current total is " << f1(10) << '\n'; std::cout << "The current total is " << f2(10) << '\n'; std::cout << "The current total is " << f3(10) << '\n'; std::cout << "After adding 10 three times, the total is " << ks.total() << '\n';

Ngày đăng: 06/07/2014, 04:20