Last active
December 31, 2015 23:59
-
-
Save Fiona-J-W/8063182 to your computer and use it in GitHub Desktop.
This file contains 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 <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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
output: