Skip to content

Instantly share code, notes, and snippets.

@Fiona-J-W
Last active December 31, 2015 18:39
Show Gist options
  • Save Fiona-J-W/8028785 to your computer and use it in GitHub Desktop.
Save Fiona-J-W/8028785 to your computer and use it in GitHub Desktop.
#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;
}
}
@Fiona-J-W
Copy link
Author

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

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