├── README.md ├── client.cpp └── library.hpp /README.md: -------------------------------------------------------------------------------- 1 | # Better Code: Runtime Polymorphism 2 | 3 | [talk-slides]: http://sean-parent.stlab.cc/presentations/2017-01-18-runtime-polymorphism/2017-01-18-runtime-polymorphism.pdf 4 | 5 | Git walk through of the C++ code presented in Sean Parent's talk [Better Code: 6 | Runtime Polymorphism][talk-slides]. 7 | 8 | Casual C++ programmers or CS undergrads will be familiar with the 9 | object-oriented code up to the "slide 13" commit. The use of the C++11 feature 10 | `std::shared_ptr` may be new and the memory leak fixed in "slide 13 (leak fix)" 11 | may cause a mild surprise. The subsequent transformations go on to show the true 12 | power of new C++ features (C++11 and C++14) and the result is _very_ client 13 | friendly code (at the price of the library containing some albeit convoluted 14 | gobbledygook C++ boilerplate). 15 | 16 | [github-commits-page]: https://github.com/alecjacobson/better-code-runtime-polymorphism/commits/master 17 | 18 | The [git commits][github-commits-page] of this repository are labeled with 19 | "slide x" where x corresponds to the slide number in the corresponding [talk by 20 | Sean parent][talk-slides] to moments where he compiles and runs the code. 21 | Through these commits you will see the transformations he applies. I have mostly 22 | faithfully copied his code examples, adding necessary `#include`s and `using 23 | namespace` lines to get it to compile. 24 | 25 | Most of the time the only necessary compilation flag is C++11 support. When 26 | `unique_ptr`s are briefly used you may need C++14. 27 | 28 | For example, on Mac OS X with Apple LLVM version 9.1.0 (clang-902.0.39.2) you 29 | can compile and run for any commit with 30 | 31 | clang++ -std=c++14 client.cpp && ./a.out 32 | -------------------------------------------------------------------------------- /client.cpp: -------------------------------------------------------------------------------- 1 | // clang++ -std=c++14 client.cpp -o client && ./client 2 | #include "library.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class my_class_t { 10 | /* ... */ 11 | }; 12 | 13 | void draw(const my_class_t&, ostream& out, size_t position) 14 | { out << string(position, ' ') << "my_class_t" << endl; } 15 | 16 | int main() { 17 | history_t h(1); 18 | current(h).emplace_back(0); 19 | current(h).emplace_back(string("Hello!")); 20 | 21 | draw(current(h), cout, 0); 22 | cout << "--------------------------" << endl; 23 | 24 | commit(h); 25 | 26 | current(h)[0] = 42.5; 27 | 28 | auto saving = async([document = current(h)]() { 29 | this_thread::sleep_for(chrono::seconds(3)); 30 | cout << "-------- 'save' --------" << endl; 31 | draw(document, cout, 0); 32 | }); 33 | 34 | current(h)[1] = string("World"); 35 | current(h).emplace_back(current(h)); 36 | current(h).emplace_back(my_class_t()); 37 | 38 | draw(current(h), cout, 0); 39 | cout << "--------------------------" << endl; 40 | 41 | undo(h); 42 | 43 | draw(current(h), cout, 0); 44 | } 45 | -------------------------------------------------------------------------------- /library.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | template 9 | void draw(const T& x, ostream& out, size_t position) 10 | { out << string(position, ' ') << x << endl; } 11 | 12 | class object_t { 13 | public: 14 | template 15 | object_t(T x) : self_(make_shared>(move(x))) 16 | { } 17 | 18 | friend void draw(const object_t& x, ostream& out, size_t position) 19 | { x.self_->draw_(out, position); } 20 | private: 21 | struct concept_t { 22 | virtual ~concept_t() = default; 23 | virtual void draw_(ostream&, size_t) const = 0; 24 | }; 25 | template 26 | struct model final : concept_t { 27 | model(T x) : data_(move(x)) { } 28 | void draw_(ostream& out, size_t position) const override 29 | { draw(data_, out, position); } 30 | 31 | T data_; 32 | }; 33 | 34 | shared_ptr self_; 35 | }; 36 | 37 | using document_t = vector; 38 | 39 | void draw(const document_t& x, ostream& out, size_t position) 40 | { 41 | out << string(position, ' ') << "" << endl; 42 | for (const auto& e: x) draw(e, out, position + 2); 43 | out << string(position, ' ') << "" << endl; 44 | } 45 | 46 | using history_t = vector; 47 | 48 | void commit(history_t& x){ assert(x.size()); x.push_back(x.back()); } 49 | void undo(history_t& x) { assert(x.size()); x.pop_back(); } 50 | document_t& current(history_t& x) { assert(x.size()); return x.back(); } 51 | --------------------------------------------------------------------------------