fork(1) download
  1. #include <iostream>
  2. #include <memory>
  3. #include <vector>
  4. using namespace std;
  5.  
  6. //This concept was taken from a Going Native 2013 talk called "C++ Seasoning" given by Sean Parent
  7. //
  8. //Located here: (about 101 minutes into it)
  9. //http://c...content-available-to-author-only...n.com/Events/GoingNative/2013/Cpp-Seasoning
  10.  
  11. //Polymorphism without inheritance.
  12. //Permits polymorphism without using pointers or references,
  13. //and allows them to be copied around easier (each instance is actually its own object) rather
  14. //than accidentally shallow-copying when you wanted deep-copies.
  15. //
  16. //Every time Object::Print() is called, it calls
  17. // Object::PrintableConcept::Print(), which virtually calls
  18. // Object::PrintableModel<TYPE>::Print(), which calls your
  19. // "derived" class that implements the Print() function, regardless
  20. // of what that class inherits (if anything).
  21. class Object //Class without inheritance or virtual.
  22. {
  23. public:
  24. template<typename Type>
  25. Object(Type instance) : self(std::make_shared<PrintableModel<Type>>(std::move(instance)))
  26. { }
  27.  
  28. //Calls the "inherited" function.
  29. void Print() const
  30. {
  31. self->Print();
  32. }
  33.  
  34. private:
  35. struct PrintableConcept //The concept we want to polymorphably access.
  36. {
  37. virtual ~PrintableConcept() = default;
  38. virtual void Print() const = 0;
  39. };
  40.  
  41. //The class that concretely models the concept,
  42. //and does the actual inheritting.
  43. template<typename Type>
  44. struct PrintableModel : public PrintableConcept
  45. {
  46. PrintableModel(Type instance) : data(std::move(instance)) { }
  47.  
  48. //Every time
  49. void Print() const override
  50. {
  51. this->data.Print();
  52. }
  53.  
  54. Type data;
  55. };
  56.  
  57. //This should be a unique_ptr, but you also need to make sure
  58. //you implement proper copy operators in this class and move support.
  59. std::shared_ptr<PrintableConcept> self;
  60. };
  61.  
  62. class Whatever
  63. {
  64. public:
  65. void Print() const { std::cout << "Whatever\n" << std::endl; }
  66. };
  67.  
  68. class SomethingElse
  69. {
  70. public:
  71. void Print() const { std::cout << "SomethingElse\n" << std::endl; }
  72. };
  73.  
  74. class WidgetThing
  75. {
  76. public:
  77. void Print() const { std::cout << "WidgetThing\n" << std::endl; }
  78. };
  79.  
  80. typedef std::vector<Object> Document;
  81.  
  82. int main()
  83. {
  84. Document document;
  85. document.emplace_back(Whatever());
  86. document.emplace_back(SomethingElse());
  87. document.emplace_back(WidgetThing());
  88.  
  89. for(const auto &object : document)
  90. {
  91. object.Print();
  92. }
  93.  
  94. return 0;
  95. }
Success #stdin #stdout 0s 3436KB
stdin
Standard input is empty
stdout
Whatever

SomethingElse

WidgetThing