// abstract base class (runtime polymorphism) class GeoObj { int x; public: GeoObj(int v) : x(v) {} }; // inheritance hierarchy struct Circle : public GeoObj { Circle(int v) : GeoObj(v) {} }; struct Square : protected GeoObj {}; struct Ellipsis : private Circle {}; // aggregation/composition struct Triangle { GeoObj g; Triangle(): g(4); }; // ad hoc polymorphism void f(); long f(int); char f(double); // compile-tyme polymorphism template void f(const GeoObj& a) { a.draw(); } template U g(U a, U b) { return a + b; } struct Te { void draw() const {} }; struct Re { void draw(int p = 0) const {} }; int main() { f(Te()); f(Re()); g(4, 5); } template class /*struct*/ example { private: T a{}; U b{}; public: ~example(); example(); example(const example &); example &operator=(const example &); example(example &&) noexcept; example &operator=(example &&) noexcept; void swap(example &); friend void swap(example &, example &) noexcept; // rule of 6 bool operator==(const example&) const noexcept; bool operator!=(const example&) const noexcept; bool operator<(const example&) const noexcept; bool operator<=(const example&) const noexcept; bool operator>(const example&) const noexcept; bool operator>=(const example&) const noexcept; friend std::ostream& operator<<(std::ostream&, const example&); // operator[] // operator+ // operator* };