mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-20 14:42:21 +00:00
212 lines
5.5 KiB
Plaintext
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] |