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

189 lines
7.1 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:tutorial03 Tutorial 3 - Multiple and Implementation Inheritance]
This tutorial shows more advanced class loading. The example described here is
contrived, and such a convoluted design is not used as an example of good
object-oriented program, but as a way to illustrate some of the possibilities
with this library.
Most complications with this type of factory usage only occur on Windows, or with
less popular compiler options. Refer to
[link boost_extension.appendices.appendix_a Appendix A].
Let's design a class hierarchy based on the following:
* There is a vehicle class
* There is a computer class
* A car is a vehicle
* A boat is a vehicle
* A plane is a vehicle
* A flying_car is a plane and a car
* A car_of_the_future is a flying_car, a boat, and a computer.
In addition, we are not going to have any of these classes be interfaces. They
will each have an implementation in a .cpp file. This will require multiple
inheritance, as well as virtual inheritance (because otherwise a
car_of_the_future would consist of three separate vehicle base classes!).
In addition, each class will be compiled into a separate shared library. This
is not necessary, certainly, but will serve to illustrate some of the more
advanced capabilities of the library, as well as some of the techniques
necessary in this situation.
To begin with, let's look at the Jamfile:
``
import type : change-generated-target-suffix ;
import type : change-generated-target-prefix ;
type.change-generated-target-suffix SHARED_LIB : : extension ;
type.change-generated-target-prefix SHARED_LIB : : lib ;
``
As usual, first we must rename the generated libraries (this is required for
cross-platform use - but the prefix and suffix are arbitrary).
Next, some special options are needed for certain compilers, to make sure
that the shared libraries are found correctly. This is only needed for this
example because we have shared libraries that are linked by the linker after
compilation to other shared libraries, rather than loaded by the shared_library
class at runtime. Library paths and includes need to be set as follows:
``
local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;
project
: requirements
<include>../../../
<include>$(BOOST_ROOT)
<toolset>gcc:<find-shared-library>dl
<toolset>gcc:<linkflags>"-Wl,-rpath,'$ORIGIN'"
<toolset>darwin:<define>DYLD_LIBRARY_PATH=./
:
;
``
The rules for building the first two libraries are the same
as those from earlier tutorials.
``
lib Vehicle : multiple_inheritance/vehicle.cpp : <link>shared ;
lib Car : multiple_inheritance/car.cpp Vehicle : <link>shared ;
``
Notice here that the Car library is linked to the Vehicle library - this is
necessary because the Car class needs the implementation of the Vehicle class.
This is not specific to the Boost.Extension library, but just a standard
requirement when inheriting from shared library classes. The same will be done
with the other shared libraries.
``
lib Plane : multiple_inheritance/plane.cpp Vehicle : <link>shared ;
lib Boat : multiple_inheritance/boat.cpp Vehicle : <link>shared ;
lib Computer : multiple_inheritance/computer.cpp : <link>shared ;
lib FlyingCar : multiple_inheritance/flying_car.cpp Plane Car Vehicle
: <link>shared ;
lib CarOfTheFuture :
multiple_inheritance/car_of_the_future.cpp
Plane Car Vehicle
FlyingCar Computer Boat
:
<link>shared
;
install ../bin :
HelloWorld HelloWorldLib Vehicle Boat FlyingCar
CarOfTheFuture MultipleInheritance
:
;
``
Refer to the examples/multiple_inheritance folder for the source code of these
classes. Only the most complex will be described here - the rest are similar.
On the Windows platform, there are special declarations that are required when
a dll must use a class that is defined in another dll. For interface only
classes this is unnecessary, and is not needed on other platforms. The macros
BOOST_EXTENSION_IMPORT_DECL and BOOST_EXTENSION_EXPORT_DECL can be used
to insert the proper declaration. This is detailed in
[link boost_extension.appendices.appendix_a Appendix A].
The macros here are defined in such a way that in the `car_of_the_future`
class, the classes it depends on from other shared libraries are
declared as imports. The BOOST_EXTENSION_CAR_OF_THE_FUTURE_DECL must be
defined by any source file using this class - as `BOOST_EXTENSION_IMPORT_DECL`
by the shared library containing the `car_of_the_future`, and as
`BOOST_EXTENSION_EXPORT_DECL` by any shared library or executable linking
directly to that shared library.
``
#define BOOST_EXTENSION_FLYING_CAR_DECL BOOST_EXTENSION_IMPORT_DECL
#define BOOST_EXTENSION_BOAT_DECL BOOST_EXTENSION_IMPORT_DECL
#define BOOST_EXTENSION_COMPUTER_DECL BOOST_EXTENSION_IMPORT_DECL
#include "flying_car.hpp"
#include "boat.hpp"
#include "computer.hpp"
#include <iostream>
#include <typeinfo>
class BOOST_EXTENSION_CAR_OF_THE_FUTURE_DECL
car_of_the_future : public flying_car, public boat, public computer
{
public:
car_of_the_future(void){std::cout << "\nCreated a Car of the Future";}
~car_of_the_future(void){std::cout << "\nDestroyed a Car of the Future";}
virtual std::string list_capabilities(void);
};
``
In the implementation file for the `car_of_the_future`, it is exported
as an implementation of each of its base classes.
``
std::string car_of_the_future::list_capabilities() {
return boat::list_capabilities() + flying_car::list_capabilities() +
computer::list_capabilities() + "\nCosts an arm and a leg";
}
using boost::extensions::factory;
BOOST_EXTENSION_TYPE_MAP_FUNCTION {
types.get<std::map<std::string, factory<vehicle> > >()
["A car of the future exported as a vehicle"].set<car_of_the_future>();
types.get<std::map<std::string, factory<car> > >()
["A car of the future exported as a car"].set<car_of_the_future>();
types.get<std::map<std::string, factory<plane> > >()
["A car of the future exported as a plane"].set<car_of_the_future>();
types.get<std::map<std::string, factory<flying_car> > >()
["A car of the future exported as a flying car"].set<car_of_the_future>();
types.get<std::map<std::string, factory<boat> > >()
["A car of the future exported as a boat"].set<car_of_the_future>();
types.get<std::map<std::string, factory<computer> > >()
["A car of the future exported as a computer"].set<car_of_the_future>();
types.get<std::map<std::string, factory<car_of_the_future> > >()
["A car of the future exported as a car of the future"].set<car_of_the_future>();
}
``
The main executable is relatively straightforward, but does introduce a new
function: `load_single_library`, which takes a _type_map_ and the location
of the shared library, and loads the library and calls the function declared
as `BOOST_EXTENSION_TYPE_MAP_FUNCTION`.
Now, place all of the compiled libraries and the main executable in a directory together,
and run the executable.
[endsect]