Class declaration
DBOO uses a declarative reflection API to understand the application’s classes and their relationships. The objective of the reflection API is to understand and support serialization of all standard containers and classes.
In short, DBOO can handle:
Any C++ primitive type.
Any class or struct type.
Any STL container (not the adapters) with elements of any type.
C-style fixed length arrays of any type.
Complex object graphs (deep copies of pointers).
Version control of class declaration.
Any type of inheritance structure.
Classes
For each class or struct that is used in the application, and that will be serialized, a class declaration must be added. In the class declaration, a class object is defined and a function that knows how to register member fields is registered with this class object.
The class registration occurs during the static initialization of the program, before the main() function is called.
Class registry
The class registry is implemented in the class cls_reg. As a user of DBOO, the only interaction with cls_reg is with the class declaration, where a call to dboo::init()
must be made.
The dboo::init()
will call all the registered classes’ class initialization functions. This is necessary for all the member fields to be registered. If you discover that your output files are storing objects without members or base classes, you most likely forgot to call dboo::init()
at program start up.
Type id/class name
All the types have an associated type id. For the primitive types and the STL containers, these are defined by the DBOO. The type id for any user defined class types must be set by the user of DBOO. The reason for this, rather than to automatically create a type id internally in DBOO by using the type_info as provided by the C++ standard is that a platform independent externalizable name must be available for the type.
Requirements on classes
There are a few requirements on the classes and structures that must be met in order to use DBOO effectively. Most of them are requirements that normally applies anyway in order to write exception safe classes. The greatest constraint is that the class must have a default constructor. The following list shows the constraints:
All non abstract classes must have a default constructor.
Any objects created by the constructor, must be destroyed by the destructor.
All pointers must be initialized to null in default constructor.
The destructor must not throw.
Any object that has been constructed in the default constructor and used to initialize pointer members may be destroyed during internalization by the serializer. Thus, constructed objects must be allowed to be destroyed without any side effects.
The types of pointed-to objects must have class objects associated with them.
A class may contain a reference as long as there is a default constructor that knows how to initialize it. References can not be serialized, and must be omitted from the member registration.
All classes must have a constructor, which must be possible to call without any arguments, (i.e. any arguments must have default values).
All serialized class members must be initialized.
The cls<> class (C++)
To describe a C++ class for DBOO, you would use the cls<> class (see API reference cls):
template<typename T>
class cls
: public cls_class_any
{
protected:
cls_class_any(const std::type_info& ti, const cls_id& id);
public:
cls(const char* id);
cls(const char* id, void (*dboo_class_init)(cls&));
void set_post_int_f(void (T::*dboo_post_internalize_mem)());
void set_post_int_f(void (*dboo_post_internalize)(T&));
void set_version(cls_version version);
virtual cls_version get_version() const;
void set_version_handler(cls_version version,
const version_handler* handler);
template<typename MT, typename C>
void member(MT C::* m, const char* name);
template<typename ST>
void base();
template<typename ST>
void base_nonpm();
};
This class is used when a user defined class is registered with DBOO. For each user defined class, a instance of this cls<> is defined in static memory. When the program starts up, before the main()
is called, all the defined class objects will be registered with cls_reg as they are initialized.
#include "dboo/rfx.h"
dboo::cls<AddressCard> cAddressCard("AddressCard");
When the dboo::init()
is called, the class’ dboo_class_init()
function, or another class initialization function if that has been declared, is invoked with the class object as argument. The class initialization function must then register any base classes and member fields.
Class initialization function (C++)
The class initialization function must be defined by the library user for each user defined class that will be serialized. In this function, all the class’ member fields and base classes must be registered. There are 3 different ways to define the class initialization function:
Use the default
dboo_class_init()
function in the user defined class.Use any other function in the user defined class with the signature
static void function(cls<T>&);
Use a global function with the signature
void function(cls<T>&);
…
The different methods gives the same functionality although they are used in slightly different circumstances.
Default: static void dboo_class_init(cls<T>&) By not specifying a function for the class object’s constructor, you must define the default function in your class. You must use the default function or a user defined class function to be able to serialize protected and private member fields and base classes.
#include "dboo/rfx.h"
class AddressCard
{
...
static void dboo_class_init(cls<AddressCard>& c)
{
...
}
};
dboo::cls<AddressCard> cAddressCard("AddressCard");
* ...
Example of the default :dboo:`dboo_class_init()`. No function pointer is passed in to the constructor of the class object.
User defined class function: static void function(cls<T>&)
This provides exactly the same functionality as the default function with the difference that the user may choose any function name. The function must be passed to the constructor of the class object.
#include "dboo/rfx.h"
class AddressCard
{
...
static void MyInitDBOO(cls<AddressCard>& c)
{
...
}
};
dboo::cls<AddressCard> cAddressCard("AddressCard", AddressCard::MyInitDBOO);
* ...
Example of user defined class function. The function pointer is passed in to the constructor of the class object.
Global function: void function(cls<T>&)
With a global class initialization function you can add serialization to a class without altering the class itself. This may be useful when the application uses 3rd party libraries or when for any other reason the class declaration cannot be touched. The constraint with this method is that only public member fields can be serialized.
#include "dboo/rfx.h"
void InitAddressCard(cls<AddressCard>& c)
{
...
}
dboo::cls<AddressCard> cAddressCard("AddressCard", InitAddressCard);
* ...
Example of user defined global function. The function pointer is passed in to the constructor of the class object.
Member Fields
Member fields are registered in the class initialization function. No matter what type the field has, the syntax is the same:
#include "dboo/rfx.h"
using namespace std;
...
void dboo_class_init(dboo::cls<AddressCard>& c) {
c.member(&AddressCard::Name, "Name");
c.member(&AddressCard::Street, "Street");
...
}
...
* ...
The function cls<Class>::member() takes the pointer to member of the field as first argument and the name of the field as the second argument. See API reference cls::member().
Base Classes
Just as member fields, base classes are registered in the class initialization function. The function cls<Class>::base<BaseClass>()
is used. It only takes the base class type as template argument. See API reference cls::base().
#include "dboo/rfx.h"
class Car
: public Vehicle
, public Engine
, public Seats
{
...
void dboo_class_init(dboo::cls<Car>& c) {
c.base<Vehicle>();
c.base<Engine>();
...
c.base_nonpm<Seats>();
...
}
...
};
* ...
Any number of base classes may be registered. Virtual base classes (C++) are serializable as well, although in the current release, multiple instances will be output to the external representation. This doesn’t cause any other problem than extra storage space.
Base classes that are not polymorphic must be added with the function base_nonpm(). The syntax is the same, but it will use slightly different code for cast operations internally.
Post Internalization Function
In some cases it is necessary to do initialization of an object after it has been internalized. This can be achieved with a post internalization function. This is set with cls<Class>::set_post_int_f() and may be either a member function or a global function. The member function doesn’t take any arguments but is invoked on the internalized object. The global function takes the internalized object as argument.
#include "dboo/rfx.h"
class AddressCard
{
...
static void dboo_class_init(cls<AddressCard>& c)
{
c.set_post_int_f(&AddressCard::my_post_init_f);
...
}
void my_post_init_f() {
...
}
};
dboo::cls<AddressCard> cAddressCard("AddressCard");
* ...
Example of a post internalization function declared as a member function.
#include "dboo/rfx.h"
void my_post_init_f(AddressCard& object) {
...
}
class AddressCard
{
...
static void dboo_class_init(cls<AddressCard>& c)
{
c.set_post_int_f(my_post_init_f);
...
}
};
dboo::cls<AddressCard> cAddressCard("AddressCard");
* ...
Example of a post internalization function declared as a global function.
The post internalization function is called after the entire object graph has been internalized. That is, all member fields and all base and sub classes of all objects in the stream have been internalized. Also, the post internalization functions of all member fields and base classes have been called prior to the call to this function. However, the post internalization function of objects pointed to may not have been invoked yet at this point.
Class function (Node.js)
The class function serves the same purpose in Node.js as the cls<> object and the class initialization function in C++. Internally, a cls<> instance is created even for Node.js code (see also dboo.class (Node.js)).
const dboo = require('dboo');
dboo.class(<class/function name>,
<base class> | [<base class 1>, <base class 2>, ...],
[{<member 1 name>: <dboo type>},
{<member 2 name>: <dboo type>}
],
{<extra params>}
);
An example of how it can be used:
const dboo = require('dboo');
class User {
userId = null;
emailAddress = "";
mobileNumber = "";
firstName = "";
lastName = "";
permissions = [];
lists = [];
friends = [];
preferred_locale = "";
constructor() {
this.userId = null;
this.emailAddress = "";
this.firstName = "";
this.lastName = "";
this.permissions = [];
this.lists = [];
this.preferred_locale = "";
}
};
exports.User = User;
dboo.class(User,
[{"userId": userid.UserId},
{"emailAddress": dboo.string},
{"firstName": dboo.string},
{"lastName": dboo.string},
{"permissions": dboo.array(dboo.string)},
{"lists": dboo.array(lists.ShoppingList)},
{"friends": dboo.array(userid.UserId)},
{"preferred_locale": dboo.string},
]
);
In this case the userid.UserId and lists.ShoppingList are other user defined classes.
The parameter <extra params> is currently not used (it is possible to set the class version by specifying {version: 1}). Support for version handling or post internalization functions will come.
Datatypes with examples
Implementation status
The following tables and examples show which datatypes and constructions are supported. Supported containers can have any other data type as key or value type. The goal is that all datatype should be possible to map to some language specific datatype and still make sense.
Primitives
In C++ it is fairly straight forward. All primitive types are supported. In Node.js, there are not that many primitive types, but Node.js API still support all the types supported for C++. In Node.js, all of them maps to Number at this point. There are no checks whether the number in a property fits in the designated DBOO type.
Data types |
Status |
Comment |
---|---|---|
All primitive types |
✅ |
1#pragma once
2#include <dboo/rfx.h>
3#include <vector>
4#include <array>
5
6class primitives
7{
8public:
9 int8_t _member_int8;
10 uint64_t _member_uint64;
11 int _member_int;
12 double _member_double;
13 long _member_long;
14 float _member_float;
15 std::array<double,13> _member_array_of_double;
16
17 inline static dboo::cls<primitives> _class{"primitives"};
18 inline static void dboo_class_init(dboo::cls<primitives>& c) {
19 c.member(&primitives::_member_int8, "_member_int8");
20 c.member(&primitives::_member_uint64, "_member_uint64");
21 c.member(&primitives::_member_int, "_member_int");
22 c.member(&primitives::_member_double, "_member_double");
23 c.member(&primitives::_member_long, "_member_long");
24 c.member(&primitives::_member_float, "_member_float");
25 c.member(&primitives::_member_array_of_double, "_member_array_of_double");
26 }
27
28};
Data types |
Status |
DBOO specifier |
Comment |
---|---|---|---|
Number |
✅ |
dboo.int |
|
. |
✅ |
dboo.uint |
|
. |
✅ |
dboo.long |
|
. |
✅ |
dboo.ulong |
|
. |
✅ |
dboo.int8 |
|
. |
✅ |
dboo.int16 |
|
. |
✅ |
dboo.int32 |
|
. |
✅ |
dboo.int64 |
Number can represent a 53 bit integer at most. |
. |
✅ |
dboo.uint8 |
|
. |
✅ |
dboo.uint16 |
|
. |
✅ |
dboo.uint32 |
|
. |
✅ |
dboo.uint64 |
Number can represent a 53 bit integer at most. |
. |
✅ |
dboo.float |
|
. |
✅ |
dboo.double |
|
. |
✅ |
dboo.ldouble |
|
bool |
✅ |
dboo.bool |
|
BigInt |
➖ |
Planned. |
1const dboo = require('dboo');
2
3class primitives {
4 _member_int8 = 0;
5 _member_uint64 = 0;
6 _member_int = 0;
7 _member_double = 0;
8 _member_long = 0;
9 _member_float = 0;
10 _member_array_of_double = [];
11
12 constructor() {
13 }
14}
15
16dboo.class(primitives, [
17 {"_member_int8": dboo.int8_t },
18 {"_member_uint64": dboo.uint64_t },
19 {"_member_int": dboo.int },
20 {"_member_double": dboo.double },
21 {"_member_long": dboo.long },
22 {"_member_float": dboo.float },
23 {"_member_array_of_double": dboo.array(dboo.double)},
24]);
Strings
Data types |
Status |
Comment |
---|---|---|
std::string |
✅ |
|
std::wstring |
✅ |
1#pragma once
2#include <dboo/rfx.h>
3
4#include <string>
5#include <list>
6
7class my_strings
8{
9public:
10 // A wide string, this has 16 or 32 bits chars...
11 std::wstring _a_wide_string;
12 // A normal string
13 std::string _a_narrow_string;
14
15 // You can put them in any stl container
16 std::list<std::string> _a_list_of_strings;
17 std::map<std::string, std::string> _a_map_of_strings;
18
19 inline static dboo::cls<my_strings> _class{"my_strings"};
20 inline static void dboo_class_init(dboo::cls<my_strings>& c) {
21 c.member(&my_strings::_a_wide_string, "_a_wide_string");
22 c.member(&my_strings::_a_narrow_string, "_a_narrow_string");
23 c.member(&my_strings::_a_list_of_strings, "_a_list_of_strings");
24 c.member(&my_strings::_a_map_of_strings, "_a_map_of_strings");
25 }
26};
Data types |
Status |
DBOO specifier |
Comment |
---|---|---|---|
String |
✅ |
dboo.string |
1const dboo = require('dboo');
2
3class my_strings {
4 // You don't really need to define them here
5 _a_string;
6 // You can put them in an array
7 _a_list_of_strings;
8 // or a map...
9 _a_map_of_strings;
10
11 constructor() {
12 // A constructor is required that should put some default values in all properties
13 this._a_string = '';
14 this._a_list_of_strings = [];
15 this._a_map_of_strings = new Map();
16 }
17}
18
19dboo.class(my_strings, [
20 {"_a_string": dboo.string },
21 {"_a_list_of_strings": dboo.array(dboo.string) },
22 {"_a_map_of_strings": dboo.map(dboo.string, dboo.string) },
23]);
Pointers and references
Data types |
Status |
Comment |
---|---|---|
std::unique_ptr |
✅ |
|
std::shared_ptr |
➖ |
Planned. |
dboo::obj_id |
✅ |
|
dboo::ref |
✅ |
Lazy loading reference |
pointer |
✅ |
To other user defined class types. |
C++ reference |
➖ |
References cannot be serialized. |
value composition |
✅ |
Where a member field is of a class type. |
1#pragma once
2#include "primitives.h"
3#include "strings.h"
4
5#include <dboo/rfx.h>
6#include <memory>
7
8class pointers {
9public:
10 pointers() = default;
11
12private:
13 // A normal C pointer. Must be nullptr initialized in default constructor (or point to a real object!!!)
14 primitives *_a_bare_pointer{nullptr};
15
16 // A unique ptr.
17 std::unique_ptr<my_strings> _a_smarter_ptr;
18
19 // A dboo::ref, which is a lazy loading pointer (retrieves object once dereferenced).
20 dboo::ref<primitives> _the_smartest_ptr;
21 friend void test_data(pointers& ptr);
22public:
23 inline static dboo::cls<pointers> _class{"pointers"};
24 inline static void dboo_class_init(dboo::cls<pointers>& c) {
25 c.member(&pointers::_a_bare_pointer, "_a_bare_pointer");
26 c.member(&pointers::_a_smarter_ptr, "_a_smarter_ptr");
27 c.member(&pointers::_the_smartest_ptr, "_the_smartest_ptr");
28 }
29};
Data types |
Status |
DBOO specifier |
Comment |
---|---|---|---|
Javascript reference |
✅ |
class name |
|
dboo::ref |
✅ |
dboo.ref(class name) |
Lazy loading referece. Retrieves object when accessing it. |
value composition |
✅ |
dboo.value(class name) |
Lazy loading referece. Retrieves object when accessing it. |
1const dboo = require('dboo');
2
3import {primitives} from './primitives.js'
4import {my_strings} from './my_strings.js'
5
6class pointers {
7 // So, trying to match this node example with the C++ examplee
8 // but obviously, js doesn't have bare pointers, or unique pointers etc
9 _a_bare_pointer; // : primitives (In C++ example, a primitives*)
10
11 _a_smarter_ptr; // : my_strings (In C++ example, a unique_ptr<_a_smarter_ptr>)
12
13 // A dboo::ref, which is a lazy loading pointer (retrieves object once dereferenced).
14 _the_smartest_ptr; // dboo::ref<primitives>
15
16 constructor() {
17 this._a_bare_pointer = null;
18 this._a_smarter_ptr = null;
19 this._the_smartest_ptr = null;
20 }
21};
22
23dboo.class(pointers, [
24 {"_a_bare_pointer": primitives },
25 {"_a_smarter_ptr": my_strings },
26 {"_the_smartest_ptr": dboo.ref(primitives) },
27 ]);
Containers
Containers |
Status |
Comment |
---|---|---|
fixed size array |
✅ |
|
vector |
✅ |
|
list |
✅ |
|
set |
✅ |
|
map |
✅ |
|
multiset |
✅ |
|
multimap |
✅ |
|
unordered_set |
✅ |
|
unordered_map |
✅ |
|
unordered_multiset |
✅ |
|
unordered_multimap |
✅ |
|
array |
✅ |
|
deque |
✅ |
|
bitset |
✅ |
|
forward_list |
✅ |
|
variant |
➖ |
Planned. |
tuple |
➖ |
Planned. |
pair |
➖ |
Planned. |
1#pragma once
2
3#include "primitives.h"
4#include "strings.h"
5
6#include <dboo/rfx.h>
7
8class key {
9public:
10 double value_a;
11 int value_b;
12 bool operator<(const key& b) const {
13 return b.value_a < b.value_b;
14 }
15 inline static dboo::cls<key> _class{"key"};
16 inline static void dboo_class_init(dboo::cls<key>& c) {
17 c.member(&key::value_a, "value_a");
18 c.member(&key::value_b, "value_b");
19 }
20};
21
22class containers {
23public:
24 containers() = default;
25
26 std::unordered_map<std::string, my_strings> _loads_of_strings;
27 std::unordered_map<std::string, my_strings*> _loads_of_string_ptrs;
28 std::unordered_map<std::string, std::unique_ptr<my_strings>> _loads_of_string_uptrs;
29
30 std::vector<double> _numbers;
31 std::vector<std::vector<std::vector<double>>> _3d_numbers;
32 double _fixed_3d_numbers[12][12][12];
33
34 std::unordered_set<double> _a_set_of_unique_numbers;
35
36 std::list<primitives> _a_list_of_primitives;
37
38 std::map<key, double> _complex_key;
39 std::unordered_set<std::unique_ptr<key>> _a_set_of_unique_keys;
40
41public:
42 inline static dboo::cls<containers> _class{"containers"};
43 inline static void dboo_class_init(dboo::cls<containers>& c) {
44 c.member(&containers::_loads_of_strings, "_loads_of_strings");
45 c.member(&containers::_loads_of_string_ptrs, "_loads_of_string_ptrs");
46 c.member(&containers::_loads_of_string_uptrs, "_loads_of_string_uptrs");
47 c.member(&containers::_numbers, "_numbers");
48 c.member(&containers::_3d_numbers, "_3d_numbers");
49 c.member(&containers::_fixed_3d_numbers, "_fixed_3d_numbers");
50 c.member(&containers::_a_set_of_unique_numbers, "_a_set_of_unique_numbers");
51 c.member(&containers::_a_list_of_primitives, "_a_list_of_primitives");
52 c.member(&containers::_complex_key, "_complex_key");
53 c.member(&containers::_a_set_of_unique_keys, "_a_set_of_unique_keys");
54 }
55};
Containers |
Status |
DBOO specifier |
Comment |
---|---|---|---|
array |
✅ |
dboo.array(<type>) |
|
Map |
✅ |
dboo.map(<key type>, <value type>) |
|
Set |
✅ |
dboo.set(<type>) |
|
array buffer |
✅ |
dboo.array_buffer(<type>) |
|
typed array |
✅ |
dboo.typed_array(<type>) |
1const dboo = require('dboo');
2
3import {primitives} from './primitives.js'
4import {my_strings} from './my_strings.js'
5
6class key {
7 value_a;
8 value_b;
9};
10
11class containers {
12 constructor() {
13 }
14
15 _loads_of_strings;
16 _loads_of_string_ptrs;
17 _loads_of_string_uptrs;
18 _numbers;
19 _3d_numbers;
20 _a_set_of_unique_numbers;
21 _a_list_of_primitives;
22 _complex_key;
23 _a_set_of_unique_keys;
24}
25
26dboo.class(containers, [
27 {"_loads_of_strings": dboo.map(dboo.string, dboo.composed(my_string)) },
28 {"_loads_of_string_ptrs": dboo.map(dboo.string, my_string) },
29 {"_loads_of_string_uptrs": dboo.map(dboo.string, my_string) },
30 {"_numbers": dboo.array(dboo.double) },
31 {"_3d_numbers": dboo.array(dboo.array(dboo.array(dboo.double))) },
32 {"_fixed_3d_numbers": dboo.array(dboo.array(dboo.array(dboo.double))) },
33 {"_a_set_of_unique_numbers": dboo.set(dboo.double) },
34 {"_a_list_of_primitives": dboo.array(primitives) },
35 {"_complex_key": dboo.map(dboo.composed(key), double) },
36 {"_a_set_of_unique_keys": dboo.set(key) }
37]);
Value composition
1#pragma once
2
3#include "primitives.h"
4#include "strings.h"
5
6#include <dboo/rfx.h>
7
8class by_value {
9public:
10 by_value() = default;
11
12 primitives _my_primitives;
13 my_strings _my_strings;
14
15public:
16 inline static dboo::cls<by_value> _class{"by_value"};
17 inline static void dboo_class_init(dboo::cls<by_value>& c) {
18 c.member(&by_value::_my_primitives, "_my_primitives");
19 c.member(&by_value::_my_strings, "_my_strings");
20 }
21};
1const dboo = require('dboo');
2
3import {primitives} from './primitives.js'
4import {my_strings} from './my_strings.js'
5
6class by_value {
7 _my_primitives; // primitives
8 _my_strings; // my_strings
9
10 constructor() {
11 this._my_primitives = {};
12 this._my_strings = {};
13 }
14}
15
16dboo.class(by_value, [
17 {"_my_primitives": dboo.value(primitives) },
18 {"_my_strings": dboo.value(my_strings) }
19]);
Inheritance
1#pragma once
2
3#include <dboo/rfx.h>
4
5class baseclass {
6public:
7 virtual ~baseclass() = default;
8 std::string id;
9public:
10 inline static dboo::cls<baseclass> _class{"baseclass"};
11 inline static void dboo_class_init(dboo::cls<baseclass>& c) {
12 c.member(&baseclass::id, "id");
13 }
14};
15
16class subclass : public baseclass {
17public:
18 subclass() = default;
19
20 std::string name;
21
22public:
23 inline static dboo::cls<subclass> _class{"subclass"};
24 inline static void dboo_class_init(dboo::cls<subclass>& c) {
25 c.base<baseclass>();
26 c.member(&subclass::name, "name");
27 }
28};
29
30class an_abstract_baseclass {
31public:
32 virtual ~an_abstract_baseclass() = default;
33 std::string some_other_property;
34
35 virtual void a_virtual_function() = 0;
36
37public:
38 inline static dboo::cls<an_abstract_baseclass> _class{dboo::abstract<an_abstract_baseclass>(), "an_abstract_baseclass"};
39 inline static void dboo_class_init(dboo::cls<an_abstract_baseclass>& c) {
40 c.member(&an_abstract_baseclass::some_other_property, "some_other_property");
41 }
42};
43
44
45class subclass2 : public baseclass, public an_abstract_baseclass {
46public:
47 subclass2() = default;
48
49 virtual void a_virtual_function() {}
50
51public:
52 inline static dboo::cls<subclass2> _class{"subclass2"};
53 inline static void dboo_class_init(dboo::cls<subclass2>& c) {
54 c.base<baseclass>();
55 c.base<an_abstract_baseclass>();
56 }
57};
1import {primitives} from "./primitives";
2
3const dboo = require('dboo');
4
5class baseclass {
6 id;
7 constructor(id = '') {
8 this.id = id;
9 }
10};
11
12dboo.class(baseclass, [
13 {"id": dboo.string },
14]);
15
16
17class subclass extends baseclass {
18 constructor(id = '', name = '') {
19 super(id);
20 this.name = name;
21 }
22
23 name;
24};
25
26
27dboo.class(subclass, [baseclass], [
28 {"name": dboo.string },
29]);
30
31
32// You probably wouldn't implement abstract classes in javascript, but this show how the classes in the C++
33// example would be defined in JS. When designing classes for use in both languages, make sure to only
34// use common elements.
35class an_abstract_baseclass {
36 constructor(value = '') {
37 this.some_other_property = value;
38 }
39
40 some_other_property;
41
42 a_virtual_function() {}
43}
44
45dboo.class(an_abstract_baseclass, [
46 {"some_other_property": dboo.string },
47]);
48
49
50
51// multiple inheritence doesn't work in javascript, so just extend one...
52class subclass2 extends baseclass {
53 constructor() {
54 super();
55 }
56
57 a_virtual_function() {
58 }
59};
60
61// DBOO still understands multiple inheritence and will populate the object with properties from
62// both base classes.
63dboo.class(subclass2, [baseclass, an_abstract_baseclass], [
64]);
Datetime
Date & time |
Status |
Comment |
---|---|---|
chrono::time_point |
✅ |
Some language/platform |
chrono::duration |
➖ |
independent support is planned. |
Date & time |
Status |
DBOO specifier |
Comment |
---|---|---|---|
Datetime |
➖ |
➖ |
Planned. |