-
Notifications
You must be signed in to change notification settings - Fork 80
/
G31_External_Polymorphism.cpp
153 lines (117 loc) · 3.86 KB
/
G31_External_Polymorphism.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**************************************************************************************************
*
* \file G31_External_Polymorphism.cpp
* \brief Guideline 31: Use External Polymorphism for Nonintrusive Runtime Polymorphism
*
* Copyright (C) 2022 Klaus Iglberger - All Rights Reserved
*
* This file is part of the supplemental material for the O'Reilly book "C++ Software Design"
* (https://www.oreilly.com/library/view/c-software-design/9781098113155/).
*
**************************************************************************************************/
//---- <Circle.h> ---------------------------------------------------------------------------------
class Circle
{
public:
explicit Circle( double radius )
: radius_( radius )
{
/* Checking that the given radius is valid */
}
double radius() const { return radius_; }
/* Several more getters and circle-specific utility functions */
private:
double radius_;
/* Several more data members */
};
//---- <Square.h> ---------------------------------------------------------------------------------
class Square
{
public:
explicit Square( double side )
: side_( side )
{
/* Checking that the given side length is valid */
}
double side() const { return side_; }
/* Several more getters and square-specific utility functions */
private:
double side_;
/* Several more data members */
};
//---- <Shape.h> ----------------------------------------------------------------------------------
#include <functional>
#include <stdexcept>
#include <utility>
class ShapeConcept
{
public:
virtual ~ShapeConcept() = default;
virtual void draw() const = 0;
// ... Potentially more polymorphic operations
};
template< typename ShapeT
, typename DrawStrategy >
class ShapeModel : public ShapeConcept
{
public:
explicit ShapeModel( ShapeT shape, DrawStrategy drawer )
: shape_{ std::move(shape) }
, drawer_{ std::move(drawer) }
{}
void draw() const override { drawer_(shape_); }
private:
ShapeT shape_;
DrawStrategy drawer_;
};
//---- <OpenGLDrawStrategy.h> ---------------------------------------------------------------------
//#include <Circle.h>
//#include <Square.h>
//#include /* OpenGL graphics library headers */
class OpenGLDrawStrategy
{
public:
explicit OpenGLDrawStrategy( /* Drawing related arguments */ )
{}
void operator()( Circle const& circle ) const
{
// ... Implementing the logic for drawing a circle by means of OpenGL
}
void operator()( Square const& square ) const
{
// ... Implementing the logic for drawing a square by means of OpenGL
}
private:
/* Drawing related data members, e.g., colors, textures, ... */
};
//---- <Main.cpp> ---------------------------------------------------------------------------------
//#include <Circle.h>
//#include <Square.h>
//#include <Shape.h>
//#include <OpenGLDrawStrategy.h>
#include <memory>
#include <vector>
int main()
{
using Shapes = std::vector<std::unique_ptr<ShapeConcept>>;
using CircleModel = ShapeModel<Circle,OpenGLDrawStrategy>;
using SquareModel = ShapeModel<Square,OpenGLDrawStrategy>;
Shapes shapes{};
// Creating some shapes, each one
// equipped with an OpenGL drawing strategy
shapes.emplace_back(
std::make_unique<CircleModel>(
Circle{2.3}, OpenGLDrawStrategy(/*...red...*/) ) );
shapes.emplace_back(
std::make_unique<SquareModel>(
Square{1.2}, OpenGLDrawStrategy(/*...green...*/) ) );
shapes.emplace_back(
std::make_unique<CircleModel>(
Circle{4.1}, OpenGLDrawStrategy(/*...blue...*/) ) );
// Drawing all shapes
for( auto const& shape : shapes )
{
shape->draw();
}
return EXIT_SUCCESS;
}