1 | // [License]
|
---|
2 | // The FreeBSD License
|
---|
3 | //
|
---|
4 | // Copyright (c) 2008-2009 Sebastian Mies <mies@edcft.de>
|
---|
5 | //
|
---|
6 | // Sebastian Mies
|
---|
7 | // Gebhardstrasse 25
|
---|
8 | // 76137 Karlsruhe
|
---|
9 | // Germany
|
---|
10 | //
|
---|
11 | // Redistribution and use in source and binary forms, with or without
|
---|
12 | // modification, are permitted provided that the following conditions are
|
---|
13 | // met:
|
---|
14 | //
|
---|
15 | // 1. Redistributions of source code must retain the above copyright
|
---|
16 | // notice, this list of conditions and the following disclaimer.
|
---|
17 | // 2. Redistributions in binary form must reproduce the above copyright
|
---|
18 | // notice, this list of conditions and the following disclaimer in the
|
---|
19 | // documentation and/or other materials provided with the distribution.
|
---|
20 | //
|
---|
21 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
|
---|
22 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
---|
24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
---|
25 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
---|
27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
---|
28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
---|
29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
---|
30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
---|
31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
32 | // [License]
|
---|
33 |
|
---|
34 | #ifndef VFACADE_HPP_
|
---|
35 | #define VFACADE_HPP_
|
---|
36 |
|
---|
37 | //--- USAGE INFORMATION --------------------------------------------------------
|
---|
38 | //
|
---|
39 | // This header is used to easily implement a virtual facade design pattern. It
|
---|
40 | // allows to specify a virtual wrapper interface to a non-virtual class. Look
|
---|
41 | // at this example:
|
---|
42 | //
|
---|
43 | // <code>
|
---|
44 | // // unspecified version
|
---|
45 | // class to_string_definition : public vfacade_interface {
|
---|
46 | // public:
|
---|
47 | // virtual string to_string() const {
|
---|
48 | // return "UNIMPLEMENTED: to_string()";
|
---|
49 | // };
|
---|
50 | // };
|
---|
51 | //
|
---|
52 | // // delegation version
|
---|
53 | // template<class T>
|
---|
54 | // class vfacade_delegation<to_string_definition, T> :
|
---|
55 | // public to_string_definition {
|
---|
56 | // public:
|
---|
57 | // virtual string to_string() const {
|
---|
58 | // return get<T>().to_string();
|
---|
59 | // }
|
---|
60 | // };
|
---|
61 | //
|
---|
62 | // // final type
|
---|
63 | // typedef vfacade<to_string_definition> vto_string;
|
---|
64 | // </code>
|
---|
65 | //
|
---|
66 | // The to_string_definition specifies an unimplemented facade interface. Its
|
---|
67 | // necessary for this class not to be pure-virtual. The vfacade_delegation
|
---|
68 | // specialization implements a delegation any another non-virtual class T.
|
---|
69 | // Finally the facade type is defined by using the vfacade template. Now,
|
---|
70 | // we can use this facade, like in the following example:
|
---|
71 | //
|
---|
72 | // <code>
|
---|
73 | // class A {
|
---|
74 | // public:
|
---|
75 | // string to_string() {
|
---|
76 | // return "a hello from class A";
|
---|
77 | // }
|
---|
78 | // };
|
---|
79 | //
|
---|
80 | // void main() {
|
---|
81 | // A something;
|
---|
82 | // vto_string to_str = something;
|
---|
83 | // cout << to_str->to_string() << endl;
|
---|
84 | // }
|
---|
85 | // </code>
|
---|
86 | //
|
---|
87 | // This example outputs "a hello from class A" by using the virtual facade. As
|
---|
88 | // defined class A does not need to know about the facade -- it just implements
|
---|
89 | // the needed methods. The to_string method is transparently bound to the
|
---|
90 | // facade by the delegation implementation.
|
---|
91 | //
|
---|
92 | // The purpose of this virtual facade is simple: whenever you need a abstract
|
---|
93 | // representation of non-virtual structures you can simply use a virtual facade.
|
---|
94 | // It carries a vtable with the delegation to the non-virtual methods and a
|
---|
95 | // pointer to the original object. Therefore it binds a vtable to a pointer
|
---|
96 | // so vtable information is stored with the pointer and not with the object
|
---|
97 | // itself.
|
---|
98 | //
|
---|
99 | //------------------------------------------------------------------------------
|
---|
100 |
|
---|
101 | // forward declaration
|
---|
102 | template<class X, class Y>
|
---|
103 | class vfacade_delegation;
|
---|
104 |
|
---|
105 | /**
|
---|
106 | * This class template implements a virtual facade using a defined interface
|
---|
107 | * X and a certain delegation specialization of vfascade_delegation<X,Y>.
|
---|
108 | *
|
---|
109 | * @author Sebastian Mies <mies@edcft.de>
|
---|
110 | */
|
---|
111 | template<class X>
|
---|
112 | class vfacade {
|
---|
113 | private:
|
---|
114 | X value;
|
---|
115 |
|
---|
116 | public:
|
---|
117 | vfacade() {
|
---|
118 | }
|
---|
119 |
|
---|
120 | template<class Y>
|
---|
121 | vfacade(const Y& _value) {
|
---|
122 | vfacade_delegation<X, Y> v;
|
---|
123 | v.set(_value);
|
---|
124 | memcpy(&value, &v, sizeof(X));
|
---|
125 | }
|
---|
126 |
|
---|
127 | template<class Y>
|
---|
128 | vfacade<X>& operator=(const Y& _value) {
|
---|
129 | vfacade_delegation<X, Y> v;
|
---|
130 | v.set(_value);
|
---|
131 | memcpy(&value, &v, sizeof(X));
|
---|
132 | return *this;
|
---|
133 | }
|
---|
134 |
|
---|
135 | vfacade(const vfacade<X>& v) {
|
---|
136 | memcpy(&value, &v.value, sizeof(X));
|
---|
137 | }
|
---|
138 |
|
---|
139 | vfacade<X>& operator=(const vfacade<X>& v ) {
|
---|
140 | memcpy(&value, &v.value, sizeof(X));
|
---|
141 | return *this;
|
---|
142 | }
|
---|
143 |
|
---|
144 | X* operator->() {
|
---|
145 | return &value;
|
---|
146 | }
|
---|
147 |
|
---|
148 | const X* operator->() const {
|
---|
149 | return &value;
|
---|
150 | }
|
---|
151 | };
|
---|
152 |
|
---|
153 | /**
|
---|
154 | * This class is used as base class for virtual facade interfaces.
|
---|
155 | *
|
---|
156 | * @author Sebastian Mies <mies@edcft.de>
|
---|
157 | */
|
---|
158 | class vfacade_interface {
|
---|
159 | template<class X> friend class vfacade;
|
---|
160 |
|
---|
161 | private:
|
---|
162 | void* value;
|
---|
163 |
|
---|
164 | protected:
|
---|
165 | template<class X> X& get() const {
|
---|
166 | return *((X*) value);
|
---|
167 | }
|
---|
168 | template<class X> void set(X& v) {
|
---|
169 | value = (void*) &v;
|
---|
170 | }
|
---|
171 |
|
---|
172 | public:
|
---|
173 | vfacade_interface() :
|
---|
174 | value(NULL) {
|
---|
175 | }
|
---|
176 |
|
---|
177 | bool is_unspecified() const {
|
---|
178 | return value == NULL;
|
---|
179 | }
|
---|
180 |
|
---|
181 | template<class Y>
|
---|
182 | Y* ptr() {
|
---|
183 | return (Y*)value;
|
---|
184 | }
|
---|
185 |
|
---|
186 | template<class Y>
|
---|
187 | const Y* ptr() const {
|
---|
188 | return (Y*)value;
|
---|
189 | }
|
---|
190 |
|
---|
191 | template<class Y>
|
---|
192 | Y& cast_to() {
|
---|
193 | return *ptr<Y>();
|
---|
194 | }
|
---|
195 |
|
---|
196 | template<class Y>
|
---|
197 | const Y& cast_to() const {
|
---|
198 | return *ptr<Y>();
|
---|
199 | }
|
---|
200 | };
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * This class is the base template for further delegation specializations.
|
---|
204 | *
|
---|
205 | * @author Sebastian Mies <mies@edcft.de>
|
---|
206 | */
|
---|
207 | template<class T, class Y>
|
---|
208 | class vfacade_delegation: public T {
|
---|
209 |
|
---|
210 | };
|
---|
211 |
|
---|
212 | #endif
|
---|