// //this example coverls all the corner cases that can happen using inherintace //in reality virtual inherintance is usually avoided, so your code would look much simpler. // #include #include #include //include inheritance extension //this header contains two extensions, that specifies inheritance type of base class // BaseClass - normal inheritance // VirtualBaseClass - when virtual inheritance is used //in order for virtual inheritance to work, InheritanceContext is required. //it can be created either internally (via configuration) or externally (pointer to context). #include using bitsery::ext::BaseClass; using bitsery::ext::VirtualBaseClass; struct Base { uint8_t x{}; //Base doesn't have to be polymorphic class, inheritance works at compile-time. }; template void serialize(S& s, Base& o) { s.value1b(o.x); } struct Derive1:virtual Base {// virtually inherits from base uint8_t y1{}; }; template void serialize(S& s, Derive1& o) { //define virtual inheritance, it will not compile if InheritanceContext is not defined in serializer/deserialzer s.ext(o, VirtualBaseClass{}); s.value1b(o.y1); } //to make it more interesting, serialize private member struct Derived2:virtual Base { explicit Derived2(uint8_t y):y2{y} {} uint8_t getY2() const { return y2; }; private: friend bitsery::Access; uint8_t y2{}; template void serialize(S& s) { //notice virtual inheritance s.ext(*this, VirtualBaseClass{}); s.value1b(y2); } }; struct MultipleInheritance: Derive1, Derived2 { explicit MultipleInheritance(uint8_t y2):Derived2{y2} {} uint8_t z{}; }; template void serialize(S& s, MultipleInheritance& o) { //has two bases, serialize them separately s.ext(o, BaseClass{}); s.ext(o, BaseClass{}); s.value1b(o.z); } namespace bitsery { // call to serialize function with Derived2 and MultipleInheritance is ambiguous, // it matches two serialize functions: Base classes non-member fnc and Derived2 member fnc // we need explicitly select which function to use template <> struct SelectSerializeFnc:UseMemberFnc {}; //multiple inheritance has non-member serialize function defined template <> struct SelectSerializeFnc:UseNonMemberFnc {}; } using namespace bitsery; // since in this example we're using virtual inheritance we need InheritanceContext as well. // InheritanceContext is default constructable and has no useful information outside of serializer/deserializer // lets create it internally, via configuration struct ConfigWithContext:DefaultConfig { //always add internal contexts to tuple using InternalContext = std::tuple; }; //some helper types using Buffer = std::vector; using Writer = AdapterWriter, ConfigWithContext>; using Reader = AdapterReader, ConfigWithContext>; int main() { MultipleInheritance data{98}; data.x = 254; data.y1 = 47; data.z = 1; Buffer buf{}; BasicSerializer ser{OutputBufferAdapter{buf}, nullptr}; ser.object(data); auto writtenSize = AdapterAccess::getWriter(ser).writtenBytesCount(); MultipleInheritance res{0}; BasicDeserializer des{InputBufferAdapter{buf.begin(), writtenSize}}; des.object(res); assert(AdapterAccess::getReader(des).error() == ReaderError::NoError && AdapterAccess::getReader(des).isCompletedSuccessfully()); assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() && data.z == res.z); assert(writtenSize == 4);//base is serialized once, because it is inherited virtually }