home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c++
- From: nikki@trmphrst.demon.co.uk (Nikki Locke)
- Path: sparky!uunet!pipex!demon!trmphrst.demon.co.uk!nikki
- Subject: Re: Clarification of Callbacks in C++
- Reply-To: nikki@trmphrst.demon.co.uk
- References: <1il5pcINNblt@news.cerf.net> <1iikcuINN6fr@news.cerf.net>
- Distribution: world
- X-Mailer: cppnews $Revision: 1.30 $
- Organization: Trumphurst Ltd.
- Lines: 90
- Date: Mon, 11 Jan 1993 13:47:51 +0000
- Message-ID: <726785271snx@trmphrst.demon.co.uk>
- Sender: usenet@demon.co.uk
-
- In article <1il5pcINNblt@news.cerf.net> hlf@nic.cerf.net (Howard Ferguson) writes:
- > I was to
- > supply my colleges who are coding in C++ with some classes written in
- > C++ which require calbacks. My point is that I should be able to
- > provide something cleaner than what I must use if I am writting a
- > C library which may be used by C++ coders ( e.g. Xview).
-
- It is pretty unusual to need callbacks as such in C++. Normally speaking,
- you would provide an abstract base class containing a virtual function.
- Users then derive their class from that abstract base, overriding the
- virtual function to do whatever their callback function would do.
-
- A typical example might be ...
-
- class Shape {
- public:
- virtual void draw() = 0;
- };
-
- A user creating a Rectangle (say) would derive from Shape. They would pass
- a Shape pointer to to your library functions, which would call draw for
- that Shape whenever they want to draw it.
-
- Of course, the situation can get more complex - e.g. when you want to
- perform some arbitrary (unknown at compile time) action on some arbitrary
- object in your library function.
-
- I have found it convenient in these cases to provide a template class
- (which I call a Command) to encapsulate such a callback ...
-
- #include <iostream.h>
-
- // You write this bit
- class Comd {
- public:
- virtual int doit() const = 0;
- };
-
- template <class X> class Command : public Comd {
- X &to;
- int (X::*f)(void);
- public:
- Command(X &destination, int (X::*function)(void))
- : f(function), to(destination) {}
- int doit() const { return (to.*f)(); }
- };
-
- int libraryFunction(const Comd &command)
- {
- // Do some internal library stuff
- if(command.doit())
- {
- return 1; // Do some stuff which depends on success
- }
- else
- {
- return 0; // Do some stuff which depends on failure
- }
- }
-
- // The user writes this bit
- class Test {
- int i;
- public:
- Test(int x) : i(x) {}
- int test1() { cout << i << " test1\n"; return 1; }
- int test2() { cout << i << " test2\n"; return 1; }
- };
-
- main()
- {
- Test t1(1), t2(2);
- Command<Test> c1(t1, &Test::test1), c2(t2, &Test::test2);
-
- libraryFunction(c1);
- libraryFunction(c2);
- return 0;
- }
-
- Obviously, this can easily be extended to allow the "callback" to take
- arguments, or have different return values. I use a similar Command class
- in my DOS text mode user interface toolkit, for attaching to buttons and
- menu options - when the button is pressed (or the option is selected), the
- Command is executed. In this context, an enhancement which springs to mind
- is undo-able Commands, which have a virtual undo function, and which
- register themselves on an undo stack (or similar).
-
- --
- Nikki Locke,Trumphurst Ltd.(PC and Unix consultancy) nikki@trmphrst.demon.co.uk
- trmphrst.demon.co.uk is NOT affiliated with ANY other sites at demon.co.uk.
-