fork download
  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4.  
  5. // наши интерфейсы...
  6. struct IObject;
  7.  
  8. struct IFoo {
  9. struct Ref; // ссылкообразный тип на данный интерфейс
  10. virtual operator IObject&() = 0; // возвращение к первоисточнику
  11. virtual void f() = 0;
  12. virtual void g() = 0;
  13. };
  14. struct IBar {
  15. struct Ref;
  16. virtual operator IObject&() = 0;
  17. virtual void b() = 0;
  18. virtual void c() = 0;
  19. };
  20.  
  21. // ссылки - это фасады пимплов
  22. struct IFoo::Ref {
  23. template<class T> struct Thunk; // а это - реализация пимпла
  24. shared_ptr<IFoo> ptr; // лень следить за копиями/ссылками; хочешь, возьми unique_ptr
  25. operator IObject&() { return *ptr; }
  26. void f() { ptr->f(); }
  27. void g() { ptr->g(); }
  28. };
  29. struct IBar::Ref {
  30. template<class T> struct Thunk;
  31. shared_ptr<IBar> ptr;
  32. operator IObject&() { return *ptr; }
  33. void b() { ptr->b(); }
  34. void c() { ptr->c(); }
  35. };
  36.  
  37. // реализации пимплов
  38. template<class T> struct IFoo::Ref::Thunk : IFoo {
  39. T* ptr; // как и просил - никакого контроля за владением (а может, всё же, хотя бы weak_ptr?)
  40. Thunk(T* p) : ptr(p) {}
  41. operator IObject&() { return *ptr; }
  42. void f() override { ptr->f(); }
  43. void g() override { ptr->g(); }
  44. };
  45. template<class T> struct IBar::Ref::Thunk : IBar {
  46. T* ptr;
  47. Thunk(T* p) : ptr(p) {}
  48. operator IObject&() { return *ptr; }
  49. void b() override { ptr->b(); }
  50. void c() override { ptr->c(); }
  51. };
  52.  
  53. // порождающая функция проксей
  54. template<class I, class T> // I явный, T выводится
  55. typename I::Ref make_proxy(T* p) {
  56. return typename I::Ref{
  57. make_shared<typename I::Ref::template Thunk<T>>(p)
  58. };
  59. }
  60.  
  61. // метаинтерфейс (должен быть объявлен после фасадов, ибо возвращает значения)
  62. struct IObject {
  63. virtual operator IFoo::Ref() = 0;
  64. virtual operator IBar::Ref() = 0;
  65. };
  66.  
  67. // вот наш класс!
  68. struct Something : IObject {
  69. operator IFoo::Ref() override { return make_proxy<IFoo>(this); }
  70. operator IBar::Ref() override { return make_proxy<IBar>(this); }
  71. void f() { cout << "Something::f\n"; }
  72. void g() { cout << "Something::g\n"; }
  73. void b() { cout << "Something::b\n"; }
  74. void c() { cout << "Something::c\n"; }
  75. };
  76.  
  77. // вот наш объект (один штучка)
  78. Something smth;
  79. IObject* lookup() { return &smth; }
  80.  
  81. // вот наш клиентский код!
  82. void doit(IFoo::Ref foo) {
  83. foo.f();
  84. foo.g();
  85. IBar::Ref bar = (IObject&)foo; // поскольку IFoo и IBar независимы, делаем up-down-каст
  86. bar.b();
  87. bar.c();
  88. }
  89.  
  90. int main() {
  91. doit(*lookup());
  92. }
  93.  
Success #stdin #stdout 0s 16064KB
stdin
Standard input is empty
stdout
Something::f
Something::g
Something::b
Something::c