private_protected_virtual_multi.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (C) 2008-2018 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  3. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  4. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  5. #include <boost/config.hpp>
  6. #ifdef BOOST_MSVC
  7. // WARNING: MSVC (at least up to VS 2015) gives a compile-time error if SFINAE
  8. // cannot introspect a member because of its private or protected access level.
  9. // That is incorrect, SFINAE should fail in these cases without generating
  10. // compile-time errors like GCC and CLang do. Therefore, currently it is not
  11. // possible to override a member that is public in one base but private or
  12. // protected in other base using this library on MSVC (that can be done instead
  13. // using this library on GCC or CLang).
  14. int main() { return 0; } // Trivial program for MSVC.
  15. #else
  16. #include <boost/contract.hpp>
  17. #include <limits>
  18. #include <cassert>
  19. class counter {
  20. // Virtual private and protected functions still declare extra
  21. // `virtual_* = 0` parameter (otherwise they cannot be overridden).
  22. protected:
  23. virtual void set(int n, boost::contract::virtual_* = 0) {
  24. boost::contract::check c = boost::contract::function()
  25. .precondition([&] {
  26. BOOST_CONTRACT_ASSERT(n <= 0);
  27. })
  28. .postcondition([&] {
  29. BOOST_CONTRACT_ASSERT(get() == n);
  30. })
  31. ;
  32. n_ = n;
  33. }
  34. private:
  35. virtual void dec(boost::contract::virtual_* = 0) {
  36. boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(get());
  37. boost::contract::check c = boost::contract::function()
  38. .precondition([&] {
  39. BOOST_CONTRACT_ASSERT(
  40. get() + 1 >= std::numeric_limits<int>::min());
  41. })
  42. .postcondition([&] {
  43. BOOST_CONTRACT_ASSERT(get() == *old_get - 1);
  44. })
  45. ;
  46. set(get() - 1);
  47. }
  48. int n_;
  49. public:
  50. virtual int get(boost::contract::virtual_* v = 0) const {
  51. int result;
  52. boost::contract::check c = boost::contract::public_function(
  53. v, result, this)
  54. .postcondition([&] (int const result) {
  55. BOOST_CONTRACT_ASSERT(result <= 0);
  56. BOOST_CONTRACT_ASSERT(result == n_);
  57. })
  58. ;
  59. return result = n_;
  60. }
  61. counter() : n_(0) {} // Should contract constructor and destructor too.
  62. void invariant() const {
  63. BOOST_CONTRACT_ASSERT(get() <= 0);
  64. }
  65. friend int main();
  66. };
  67. //[private_protected_virtual_multi_countable
  68. class countable {
  69. public:
  70. void invariant() const {
  71. BOOST_CONTRACT_ASSERT(get() <= 0);
  72. }
  73. virtual void dec(boost::contract::virtual_* v = 0) = 0;
  74. virtual void set(int n, boost::contract::virtual_* v = 0) = 0;
  75. virtual int get(boost::contract::virtual_* v = 0) const = 0;
  76. };
  77. /* ... */
  78. //]
  79. void countable::dec(boost::contract::virtual_* v) {
  80. boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get());
  81. boost::contract::check c = boost::contract::public_function(v, this)
  82. .precondition([&] {
  83. BOOST_CONTRACT_ASSERT(get() > std::numeric_limits<int>::min());
  84. })
  85. .postcondition([&] {
  86. BOOST_CONTRACT_ASSERT(get() < *old_get);
  87. })
  88. ;
  89. assert(false); // Never executed by this library.
  90. }
  91. void countable::set(int n, boost::contract::virtual_* v) {
  92. boost::contract::check c = boost::contract::public_function(
  93. v, this)
  94. .precondition([&] {
  95. BOOST_CONTRACT_ASSERT(n <= 0);
  96. })
  97. .postcondition([&] {
  98. BOOST_CONTRACT_ASSERT(get() == n);
  99. })
  100. ;
  101. assert(false); // Never executed by this library.
  102. }
  103. int countable::get(boost::contract::virtual_* v) const {
  104. int result;
  105. boost::contract::check c = boost::contract::public_function(
  106. v, result, this);
  107. assert(false); // Never executed by this library.
  108. }
  109. //[private_protected_virtual_multi_counter10
  110. class counter10
  111. #define BASES public countable, public counter // Multiple inheritance.
  112. : BASES
  113. {
  114. public:
  115. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  116. #undef BASES
  117. // Overriding from public members from `countable` so use `override_...`.
  118. virtual void set(int n, boost::contract::virtual_* v = 0) /* override */ {
  119. boost::contract::check c = boost::contract::public_function<
  120. override_set>(v, &counter10::set, this, n)
  121. .precondition([&] {
  122. BOOST_CONTRACT_ASSERT(n % 10 == 0);
  123. })
  124. .postcondition([&] {
  125. BOOST_CONTRACT_ASSERT(get() == n);
  126. })
  127. ;
  128. counter::set(n);
  129. }
  130. virtual void dec(boost::contract::virtual_* v = 0) /* override */ {
  131. boost::contract::old_ptr<int> old_get = BOOST_CONTRACT_OLDOF(v, get());
  132. boost::contract::check c = boost::contract::public_function<
  133. override_dec>(v, &counter10::dec, this)
  134. .precondition([&] {
  135. BOOST_CONTRACT_ASSERT(
  136. get() + 10 >= std::numeric_limits<int>::min());
  137. })
  138. .postcondition([&] {
  139. BOOST_CONTRACT_ASSERT(get() == *old_get - 10);
  140. })
  141. ;
  142. set(get() - 10);
  143. }
  144. BOOST_CONTRACT_OVERRIDES(set, dec)
  145. /* ... */
  146. //]
  147. virtual int get(boost::contract::virtual_* v = 0) const {
  148. int result;
  149. boost::contract::check c = boost::contract::public_function<
  150. override_get>(v, result, &counter10::get, this);
  151. return result = counter::get();
  152. }
  153. BOOST_CONTRACT_OVERRIDE(get)
  154. // Should contract default constructor and destructor too.
  155. void invariant() const {
  156. BOOST_CONTRACT_ASSERT(get() % 10 == 0);
  157. }
  158. };
  159. int main() {
  160. counter cnt;
  161. assert(cnt.get() == 0);
  162. cnt.dec();
  163. assert(cnt.get() == -1);
  164. counter10 cnt10;
  165. countable& b = cnt10; // Polymorphic calls.
  166. assert(b.get() == 0);
  167. b.dec();
  168. assert(b.get() == -10);
  169. return 0;
  170. }
  171. #endif // MSVC