2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-20 14:42:21 +00:00
Files
fiber/libs/extension/doc/tutorial2.qbk
Oliver Kowalke 39ec793737 initial checkin
2011-02-09 18:41:35 +01:00

212 lines
5.5 KiB
Plaintext

[/ Boost.Extension - second tutorial ]
[/ Copyright 2008 Jeremy Pack ]
[/ Distributed under the Boost Software License, Version 1.0. (See]
[/ accompanying file LICENSE_1_0.txt or copy at ]
[/ http://www.boost.org/LICENSE_1_0.txt) ]
[/ See http://www.boost.org/ for latest version. ]
[section:tutorial02 Tutorial 2 - Basic Factories]
The easiest method for creating plugins in C++ is to use factories.
Consider the following base class:
``
class animal {
public:
animal(int age) : age_(age) {
}
virtual ~animal(void) {
}
virtual std::string get_name(void) {
return "A generic animal";
}
int get_age(void) {
return age_;
}
protected:
int age_;
};
``
The goal here is to create a main executable which creates and uses
instances of the `animal` class. A shared library will then be created
which includes classes derived from the `animal` class, which the main
executable will also be able to load and use as `animal`s.
The main executable will use a number of Extension and other Boost headers:
``
#include <iostream>
#include <map>
#include <boost/extension/factory.hpp>
#include <boost/extension/shared_library.hpp>
#include <boost/extension/type_map.hpp>
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
``
It will also use the `animal` header, which will also be used by the
shared library:
``
#include "animal.hpp"
``
The main function is similar to that from
[link boost_extension.tutorials.tutorial01 Tutorial 1].
``
int main() {
using namespace boost::extensions;
std::string library_path = "libtutorial_2.extension";
// Create shared_library object with the relative or absolute
// path to the shared library.
shared_library lib(library_path);
// Attempt to open the shared library.
if (!lib.open()) {
std::cerr << "Library failed to open: " << library_path << std::endl;
return 1;
}
``
Here though, instead of using the _shared_library_get_ function, we use the
_shared_library_call_ function. It expects a function with the following signature:
``
extern "C" void boost_extension_exported_type_map_function
(boost::extensions::type_map& types);
``
A _type_map_ is a generic container with items indexed by type - only one
item of each type can be contained in it. To retrieve (or add) an integer
to it, do the following:
``
int& my_int(my_type_map.get());
``
For the rationale of the _type_map_ class, see the discussion on
[link boost_extension.type_safety type safety].
``
// Use the shared_library::call to automatically call an
// Extension-specific function in the shared library,
// which takes a type_map.
type_map types;
if (!lib.call(types)) {
std::cerr << "Function not found!" << std::endl;
return 1;
}
``
Now, a `std::map` of factories, indexed by `std::string` is retrieved from
the _type_map_ that was sent to the shared library.
The _factory_ is declared as `factory<animal, int>` meaning it returns pointers
to instances of the `animal` class, and that it is used for constructors taking
integer arguments.
``
// Retrieve a map of all animal factories taking an int and indexed
// by a string from the type_map.
std::map<std::string, factory<animal, int> >& factories(types.get());
if (factories.empty()) {
std::cerr << "Animals not found!" << std::endl;
return 1;
}
``
Now, iterate through the factory, creating each available `animal`.
``
// Create each animal.
int age = 1;
for (std::map<std::string, factory<animal, int> >::iterator it
= factories.begin();
it != factories.end(); ++it) {
++age;
std::cout << "Creating an animal using factory: " << it->first << std::endl;
boost::scoped_ptr<animal> current_animal(it->second.create(age));
std::cout << "Created an animal: " << current_animal->get_name()
<< " Age: " << current_animal->get_age() << std::endl;
}
}
``
Now, the shared library will define a number of animals. It will
use the following headers:
``
#include <iostream>
#include <map>
#include <boost/extension/extension.hpp>
#include <boost/extension/factory.hpp>
#include <boost/extension/type_map.hpp>
#include "animal.hpp"
``
The following animals will be exported:
``
class puma : public animal {
public:
puma(int age) : animal(age) {}
virtual std::string get_name() {
return "puma";
}
};
class leopard : public animal {
public:
leopard(int age) : animal(age) {}
virtual std::string get_name() {
return "leopard";
}
};
class wildcat : public animal {
public:
wildcat(int age) : animal(age) {}
virtual std::string get_name() {
return "wildcat";
}
};
class cougar : public animal {
public:
cougar(int age) : animal(age) {}
virtual std::string get_name() {
return "cougar";
}
};
``
The `BOOST_EXTENSION_TYPE_MAP_FUNCTION` declaration can be used in place
of a function declaration to automatically insert the function definition
referred to above, that takes a _type_map_. See `<boost/extension/extension.hpp>`
for more details.
``
BOOST_EXTENSION_TYPE_MAP_FUNCTION {
using namespace boost::extensions;
std::map<std::string, factory<animal, int> >&
animal_factories(types.get());
animal_factories["Puma factory"].set<puma>();
animal_factories["Leopard factory"].set<leopard>();
animal_factories["Wildcat factory"].set<wildcat>();
animal_factories["Cougar factory"].set<cougar>();
}
``
Now, compile the shared library and main executable. Then run the main executable
in the directory with the compiled library. If all is successful, a message will
be printed out for each animal.
[endsect]