Last active
December 31, 2015 18:39
-
-
Save Fiona-J-W/8028785 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cmath> | |
#include <cstddef> | |
#include <iostream> | |
#include <memory> | |
#include <utility> | |
#include <vector> | |
template<typename T, typename... Args> | |
std::unique_ptr<T> make_unique(Args&&... args) { | |
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | |
} | |
class shape_list { | |
struct shape { | |
virtual ~shape() = default; | |
virtual std::unique_ptr<shape> clone() const = 0; | |
virtual double get_area() const = 0; | |
}; | |
template<typename T> struct shape_impl : shape { | |
T value; | |
shape_impl(T val) : value{std::move(val)} {} | |
std::unique_ptr<shape> clone() const final override { | |
return make_unique<shape_impl<T>>(value); | |
} | |
double get_area() const final override { | |
return value.get_area(); | |
} | |
}; | |
std::vector<std::unique_ptr<shape>> shapes; | |
public: | |
shape_list() = default; | |
shape_list(shape_list&&) = default; | |
shape_list(const shape_list& other) { | |
for(const auto& shape: other.shapes) { | |
shapes.push_back(shape->clone()); | |
} | |
} | |
shape_list& operator=(shape_list&&) = default; | |
shape_list& operator=(const shape_list& other) { | |
if(this == &other) { | |
return *this; | |
} | |
shapes.clear(); | |
for(const auto& shape: other.shapes) { | |
shapes.push_back(shape->clone()); | |
} | |
return *this; | |
} | |
template<typename T> | |
void add(T value) { | |
shapes.push_back(make_unique<shape_impl<T>>(std::move(value))); | |
} | |
template<typename T> | |
T& get(size_t index) { | |
return dynamic_cast<shape_impl<T>&>(*(shapes.at(index).get())).value; | |
} | |
template<typename T> | |
const T& get(size_t index) const { | |
return dynamic_cast<const shape_impl<T>&>(*(shapes.at(index).get())).value; | |
} | |
double get_area(size_t index) const { | |
return shapes.at(index)->get_area(); | |
} | |
}; | |
class rectangle { | |
double height; | |
double width; | |
public: | |
rectangle(double h, double w) : height{h}, width{w} {} | |
double get_area() const { | |
return height * width; | |
} | |
double get_height() const { | |
return height; | |
} | |
double get_width() const { | |
return width; | |
} | |
}; | |
class circle { | |
double radius; | |
public: | |
circle(double radius) : radius{radius} {} | |
double get_area() const { | |
return radius * radius * M_PI; | |
} | |
double get_radius() const { | |
return radius; | |
} | |
}; | |
int main() { | |
shape_list shapes; | |
shapes.add(rectangle{3.5, 4.0}); | |
shapes.add(circle{4.3}); | |
std::cout << "shapes[0].area: " << shapes.get_area(0) << ", shapes[1].area: " | |
<< shapes.get_area(1) << '\n'; | |
std::cout << "shapes[0](rectangle): width = " << shapes.get<rectangle>(0).get_width() | |
<< ", height = " << shapes.get<rectangle>(0).get_height() << '\n'; | |
std::cout << "shapes[1](circle): radius = " << shapes.get<circle>(1).get_radius() << '\n'; | |
try { | |
std::cout << "and now: let's try what happens in case of an invalid cast:" << std::endl; | |
(void) shapes.get<circle>(0); | |
} | |
catch (std::bad_cast& e) { | |
std::cout << "caught a bad cast: " << e.what() << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The output is:
shapes[0].area: 14, shapes[1].area: 58.088
shapes0: width = 4, height = 3.5
shapes1: radius = 4.3
and now: let's try what happens in case of an invalid cast:
caught a bad cast: std::bad_cast
To compile:
g++/clang++ -Wall -Wextra -pedantic -std=c++11 -O3 gistfile1.cpp