Skip to content

Instantly share code, notes, and snippets.

@Fiona-J-W
Last active December 31, 2015 23:59
Show Gist options
  • Save Fiona-J-W/8063182 to your computer and use it in GitHub Desktop.
Save Fiona-J-W/8063182 to your computer and use it in GitHub Desktop.
#include <cmath>
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#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_group {
public:
struct shape {
virtual ~shape() = default;
virtual std::unique_ptr<shape> clone() const = 0;
virtual double get_area() const = 0;
virtual std::string to_string() const = 0;
};
shape_group() = default;
shape_group(shape_group&&) = default;
shape_group(const shape_group& other) {
for(const auto& shape: other.shapes) {
shapes.push_back(shape->clone());
}
}
shape_group& operator=(shape_group&&) = default;
shape_group& operator=(const shape_group& 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();
}
double get_area() const {
double total_area = 0.0;
for(const auto& shape : shapes) {
total_area += shape->get_area();
}
return total_area;
}
std::string to_string() const {
std::string returnstring = "group{";
auto it = shapes.begin();
auto end = shapes.end();
if(it != end) {
--end;
while(it != end) {
returnstring += (*it)->to_string();
returnstring += ", ";
++it;
}
returnstring += (*it)->to_string();
}
returnstring += '}';
return returnstring;
}
private:
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::string to_string() const final override {
return value.to_string();
}
};
std::vector<std::unique_ptr<shape>> shapes;
};
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;
}
std::string to_string() const {
return "rect{h=" + std::to_string(height) + ", w=" + std::to_string(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;
}
std::string to_string() const {
return "circle{r=" + std::to_string(radius) + "}";
}
};
int main() {
shape_group shapes;
shapes.add(rectangle{3.5, 4.0});
shapes.add(circle{4.3});
shapes.add(shapes);
std::cout << "shapes[0].area: " << shapes.get_area(0) << ", shapes[1].area: "
<< shapes.get_area(1) << ", shapes[2].area: " << shapes.get_area(2) << '\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';
std::cout << "shapes = " << shapes.to_string() << '\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;
}
}
@Fiona-J-W
Copy link
Author

output:


shapes[0].area: 14, shapes[1].area: 58.088, shapes[2].area: 72.088
shapes[0](rectangle): width = 4, height = 3.5
shapes[1](circle): radius = 4.3
shapes = group{rect{h=3.500000, w=4.000000}, circle{r=4.300000}, group{rect{h=3.500000, w=4.000000}, circle{r=4.300000}}}
and now: let's try what happens in case of an invalid cast:
caught a bad cast: std::bad_cast

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment