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

HandBooks Professional Java-C-Scrip-SQL part 100 pps

6 54 0

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 35,13 KB

Nội dung

#include <iostream> #include "boost/signals.hpp" class slot { public: void operator()() const { std::cout << "Something important just happened!\n"; } }; int main() { boost::signal<void ()> sig; { boost::signals::scoped_connection s=sig.connect(slot()); } sig(); } The boost::signals::scoped_connection s is given a small scope inside of main, and after leaving that scope the signal sig is invoked. There is no output from that, because the scoped_connection has already terminated the connection between the slot and the signal. Using scoped resources like this simplifies the code and maintenance thereof. Creating Slots Using Bind and Lambda You've seen how useful and flexible Signals is. However, you'll find even more power when you combine Boost.Signals with Boost.Bind and Boost.Lambda. Those two libraries, covered in detail in "Library 9: Bind 9" and "Library 10: Lambda 10," help to create function objects on-the-fly. That means it is possible to create slots (and slot types) right at the point where they are connected to a signal, rather than having to write a special, single-purpose class for a slot, create an instance, and then connect it. It also puts the slot logic right where it's used rather than in a separate part of the source code. Finally, these libraries even make it possible to adapt existing classes that don't provide a function call operator but have other, suitable means for handling signals. In the first example to follow, we'll have a look at how neatly lambda expressions can be used to create a few slot types. The slots will be created right in the call to connect. The first one simply prints a message to std::cout when the slot is invoked. The second checks the value of the string passed through the signal to the slot. If it equals "Signal", it prints one message; otherwise, it prints another message. (These examples are rather contrived, but the expressions could perform any kind of useful computation.) The last two slots created in the example will do exactly what double_slot and plus_slot did in an example earlier in the chapter. You'll find the lambda versions far more readable. #include <iostream> #include <string> #include <cassert> #include "boost/signals.hpp" #include "boost/lambda/lambda.hpp" #include "boost/lambda/if.hpp" int main() { using namespace boost::lambda; boost::signal<void (std::string)> sig; sig.connect(var(std::cout) << "Something happened: " << _1 << '\n'); sig.connect( if_(_1=="Signal") [ var(std::cout) << "Ok, I've got it\n"] .else_[ std::cout << constant("Yeah, whatever\n")]); sig("Signal"); sig("Another signal"); boost::signal<void (int&)> sig2; sig2.connect(0,_1*=2); // Double it sig2.connect(1,_1+=3); // Add 3 int i=12; sig2(i); assert(i==27); } If you aren't yet familiar with lambda expressions in C++ (or otherwise), don't worry if the preceding seems a bit confusingyou may want to read the chapters on Bind and Lambda first and return to these examples. If you already have, I am sure that you appreciate the terse code that results from using lambda expressions; and it avoids cluttering the code with small function objects, too. Now let 's take a look at using binders to create slot types. Slots must implement a function call operator, but not all classes that would otherwise be suitable as slots do so. In those cases, it's often possible to use existing member functions of classes, repac kaged for use as slots using binders. Binders can also help readability by allowing the function (rather than function object) that handles an event to have a meaningful name. Finally, there are situations in which the same object must respond to different events, each with the same slot signature, but different reactions. Thus, such objects need different member functions to be called for different events. In each of these cases, there is no function call operator suitable for connecting to a signal. Thus, a configurable function object is needed, and Boost.Bind provides (as the bind facility in Boost.Lambda) the means to do that. Consider a signal that expects a slot type that returns bool and accepts an argument of type double. Assuming a class some_class with a member function some_function that has the correct signature, how do you connect some_class::some_function to the signal? One way would be to add a function call operator to some_class, and have the function call operator forward the call to some_function. That means changing the class interface unnecessarily and it doesn't scale well. A binder works much better. #include <iostream> #include "boost/signals.hpp" #include "boost/bind.hpp" class some_class { public: bool some_function(double d) { return d>3.14; } bool another_function(double d) { return d<0.0; } }; int main() { boost::signal<bool (double)> sig0; boost::signal<bool (double)> sig1; some_class sc; sig0.connect( boost::bind(&some_class::some_function,&sc,_1)); sig1.connect( boost::bind(&some_class::another_function,&sc,_1)); sig0(3.1); sig1(-12.78); } Binding this way has an interesting side effect: It avoids unnecessary copying of some_class instances. The binder holds a pointer to the some_class instance and it's the binder that the signal copies. Unfortunately, there's a potential lifetime management issue with this approach: If sc is destroyed and then one of the signal s is invoked, undefined behavior results. That's because the binder will have a dangling pointer to sc. By avoiding the copies, we must also assume the responsibility of keeping the slots alive so long as a connection exists that (indirectly) references them. Of course, that's what reference-counting smart pointers are for, so the problem is easy to solve. Using binders like this is common when using Boost.Signals. Whether you use lambda expressions to create your slots or binders to adapt existing classes for use as slot types, you'll soon value the synergy among Boost.Signals, Boost.Lambda, and Boost.Bind. It will save you time and make your code elegant and succinct. Signals Summary Use Signals when  You need robust callbacks  There can be multiple handlers of events  The connection between the signal and the connected slots should be configurable at runtime That Boost.Signals supersedes old-style callbacks should be blatantly clear by now, and this library is one of the best signals and slots implementations available. The design pattern that the library captures is well known and has been studied for a long time, so the domain is mature. Some programming languages already have such mechanisms available directly in the languagefor example, delegates and events in .NET. In C++, the problem is elegantly solved with libraries. Signals and slots are used to separate the trigger mechanism of an event from the code that handles it. This separation decouples subsystems and makes them more comprehensible. It also solves the problem of updating multiple interested parties when important events take place. There are numerous places in a typical program or library where signals and slots are useful. Whether you are writing a GUI framework or an intrusion detection system for a power plant, Signals is ready to take care of all your signaling needs. It is easy to learn how to use, yet it also offers the advanced functionality that is required for complex tasks. For example, custom Combiners make it possible to write event mechanisms that are tailor-made for a certain domain. Boost.Signals was written by Douglas Gregor (who incidentally also wrote Boost.Function). This is a great library; thank you Doug! Endnotes 2. The Boost.Signals library and the Boost.Regex library are the only libraries covered in this book that actually require compiling and linking for use. The process is simple, and it's described in great detail in the online documentation, so I won't cover it here. 3. binary_search has the attractive complexity O(logN). 1.1 Introduction The Objective-C Pocket Reference is a quick guide to the Objective-C programming language and some of its fundamental support libraries. This reference takes the form of brief explanations interspersed with examples and definitions. If you are experienced with Objective-C, this handbook will supply the definitions and examples you most often need to jog your memory. If you are coming to Objective-C from C++ or Java and prefer to jump right in and write code, this book will give you enough explanation to use the language's features appropriately. You should be familiar with C-style languages in order to read this book. Objective-C uses C syntax. This book focuses only on Objective-C, and assumes that you understand the underlying C code. This handbook progresses in sequence as much as possible, with later sections building on earlier ones, but some parts are necessarily interrelated. For example, the section on objects needs to refer to classes and vice versa. Both use the terminology of inheritance. Where you see an unfamiliar term used, check the index: it is probably defined elsewhere in the book. . then connect it. It also puts the slot logic right where it's used rather than in a separate part of the source code. Finally, these libraries even make it possible to adapt existing classes. and makes them more comprehensible. It also solves the problem of updating multiple interested parties when important events take place. There are numerous places in a typical program or library. progresses in sequence as much as possible, with later sections building on earlier ones, but some parts are necessarily interrelated. For example, the section on objects needs to refer to classes

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

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN