1 / 22

An extension to the subtype relationship in C++

This presentation explores an extension to the subtype relationship in C++, allowing for maximal separation of functionalities and collaboration-based design. Practical experiences and examples are provided.

Download Presentation

An extension to the subtype relationship in C++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. An extension to the subtype relationship in C++ István Zólyomi, Zoltán Porkoláb and Tamás Kozsik Eötvös Loránd University, Budapest, Hungary {scamel | gsd | kto}@elte.hu

  2. The structure of this presentation • Motivation with examples • Loki::Typelist (short reminder) • Creating the Family hierarchy • Converting between families • Inclusion polymorphism (FamilyPtr and FamilyRef) • Practical experiences • Summary

  3. Motivation • Maximal separation of functionalities • Collaboration based design • Better maintenanceof code • Easier to create classes with required behavior • Create and handle classes as a collection of independent components

  4. Example 1 Vehicle Emergency Car Truck EmergencyVehicle PoliceCar FireEngine

  5. ios virtual virtual virtual istream ostream iostream fstreambase ifstream ofstream fstream

  6. Possible solutions • Virtual inheritance • Intrusive: specified in base classes • More concerns implies exponential number of virtual bases • Traits • No subtype relationship using hierarchies in traits • AOP, MDSC, CF • are for slightly different problems • are extensions to standard C++ • Families: subtype relationship implemented with metaprogramming • Non-intrusive solution based on the C++ standard

  7. Terminology • Class: implementation of a concern • Orthogonal concerns in independent hierarchies • Collaboration-based design: combining concerns • Collect concerns to gain required behavior • Family: instrument to express collaboration of concerns • Implemented as a single class template • Collects concern classes as a mixin using multiple inheritance • OO languages support conversions to a single concern (base) • do not support conversions between families (collections of concerns)

  8. Example 2 (Harold Ossher) OpEval OpCheck OpDisplay Operator PlusEval PlusCheck PlusDisplay Plus

  9. Loki::Typelist • Introduced by Andrei Alexandrescu (and others) • Handles meta-information (types) in compile time like conventional containers do with data in runtime <class Head, class Tail> struct Typelist { … }; • Any number of types can be listed using recursion typedef Typelist<char, Typelist<short, Typelist<int, NullType> > > Scalars; • The last element of every list is Loki::NullType by convention(like \0 for C-strings)

  10. Loki::Typelist (cont.) • We can make the previous class definition linear with predefined macros with NullType included • Typelist has many operations in Loki: appending, indexed access, removing duplicates, etc typedef TYPELIST_3(char,short,int) TheSameList; typedef Append<Scalars, TYPELIST_1(long)>::Result ExtendedList;

  11. Source code of family construction template <class List> struct Family; template <class Head, class Tail> struct Family< Typelist<Head,Tail> > : public Head, public Family<Tail> { // --- Type name shortcuts typedef Family<Tail> Rest; typedef Family< Typelist<Head,Tail> > MyType; // --- Copy constructor Family(const MyType& mt) : Head(mt), Rest(mt) {} // --- "Recursive" constructor Family(const Head& head, const Rest& rest): Head(head), Rest(rest) {} }; template <class Head> struct Family< Typelist<Head,NullType> > : public Head { // --- All in one constructor Family(const Head& head) : Head(head) {} };

  12. FAMILY_3(OpDisplay, OpEval, OpCheck) op;

  13. Conversions between families • Initialize the head class for each recursion step • Template constructors provide conversion steps (the same for operator=) template <class Head, class Tail> template <class FromType> Family< Typelist<Head,Tail> > :: Family(const FromType& f): Head(f), Family<Tail>(f) {} • Example of usage: FAMILY_3(PlusEval,PlusDisplay, PlusCheck) sum; FAMILY_2(OpEval,OpCheck) calculate; calculate = sum;

  14. Advantages • Type safe: based on builtin language conversions • Efficient: no temporal families or objects are used, objects are initialized directly • General and transparent: not restricted to families only, any user object can be converted without explicit conversion call. struct Minus: public MinusEval, public MinusDisplay, public MinusCheck {}; Minus subtract; calculate = subtract;

  15. Limitations • No duplicates in typelists or compile error • Keyword explicit is suppressed because of explicit constructor calls during conversion • Compilation fails if there is no default or copy constructor and assignment operator

  16. Smart pointers • Problems: • Conversion copies objects by value (slicing) • No dynamic binding • Solution: smart pointers • Implementation and usage similar to those of Family FAMILY_3(PlusDisplay, PlusEval, PlusCheck) sum; FAMILYPTR_2(OpDisplay, OpEval) opPtr(sum); // --- Function call with explicit cast static_cast<OpDisplay*>(opPtr)->show(); // --- In longer form with implicit cast OpDisplay *displayPtr = opPtr; displayPtr->show();

  17. FAMILYPTR_1(OpEval) OpEval *head FAMILYPTR_2(OpDisplay,OpEval) OpDisplay *head FAMILYPTR_2(OpDisplay, OpEval) opPtr; points to head: OpDisplay* head: OpEval* points to PlusDisplay PlusCheck PlusEval

  18. FamilyRef • Similar to FamilyPtr • Store references instead of pointers • Consequences: • A FamilyRef object must be initialized • Initializes by reference but copies by value during assignment FAMILY_3(PlusDisplay, PlusEval, PlusCheck) sum; // --- Initializes by reference FAMILYREF_3(OpDisplay, OpEval, OpCheck) exprRef(sum); // --- Copies by value exprRef = sum;

  19. #include <iostream> #include "family.h" struct Shape { virtual void f() { std::cout <<"Shape"; } }; struct Circle : public Shape { void f() { std::cout <<"Circle"; } }; struct Colored {}; struct Filled {}; void main() { FAMILY_3(Circle,Colored, Filled) extCircle; FAMILY_3(Colored, Filled, Shape)extShape(extCircle); FAMILY_2(Filled, Colored)extensions(extCircle); extensions = extShape = extCircle; FAMILYPTR_3(Colored, Filled, Shape)extShapePtr(extCircle); Shape* shapePtr = extShapePtr; shapePtr->f(); // --- Prints “Circle” FAMILYPTR_3(Filled, Colored, Circle)extCirclePtr(extCircle); extShapePtr = extCircle; // --- Object -> Pointer extShapePtr = extCirclePtr; // --- Der. Pointer -> Base Pointer extShape = extShapePtr; // --- Pointer -> Object (by value) }

  20. Experiences

  21. Summary • Support for collaboration based design • Implementation uses Loki::Typelist • Non-intrusive solution • Easy to understand and manage • No extension to C++ • Bad experience with compilers vs standards • Features: • Composition of concerns in a single class (Family) • Conversion between related families • Dynamic binding with smart pointers and references

  22. scamel@elte.hu gsd@elte.hu kto@elte.hu Eötvös Loránd University, Budapest, Hungary István Zólyomi Zoltán Porkoláb Tamás Kozsik Download source from http://gsd.web.elte.hu

More Related