Lesson 1 - From Structure to Class
by Zoran Horvat @zoranh75
In this lesson we will start developing an object-oriented code through which
we plan to describe all major object-oriented concepts.
Problem on which we will demonstrate programming techniques is quite simple.
Suppose that we wish to describe 2D geometric figures: circles, rectangles,
triangles, ellipses, polygons, etc. More specific requests will be added as we
progress through the lessons. At this stage we will only say that each shape is
defined by its location and other parameters which are shape-specific (e.g.
radius for circle, width and height for rectangle, etc.). In addition, every
shape will be given an optional user-friendly name. This list of requirements
is sufficient for us to start coding.
Background in Structures
Historically, objects did not come out of nowhere. They have evolved from
structures, or data records if you wish. We will start developing our 2D
geometry code by by first defining a shape, as a yet unknown geometric figure
which only has its location and given name exposed. All other features will
come later. As of this moment, we are only interested in knowing a point (x, y)
which defines position of the shape in two-dimensional Cartesian space, as well
as an array of characters which contains shape's user-friendly name. Actual
meaning of the "location" will be deferred to particular, specialized shapes.
For circle and ellipse, center will be the location; for rectangle, its lower
left corner will be the location. These details are of no importance at this
Here is the structure in C programming language which defines shape as
This piece of code declares a record containing two floating point values for
coordinates and pointer to characters for shape's name. Name is appointed in
form of an array of characters, which is recorded on the heap, i.e. outside the Shape structure itself, with only pointer kept in the Shape record. The following picture shows two instances of the Shape structure allocated dynamically on heap and pointed to by two local pointer
variables. Each of the Shape structures also points to the array of characters allocated on heap to contain
Adding Functions to Operate on Structure
Now that we have a structure defined, we will write a couple of functions to
make it operational. But before defining the functions, we will first mention
several coding conventions which we will follow. It would be worth the effort
to follow logic of object-oriented programming, since we are on the course of
writing object-oriented code. First convention will be writing a so-called
constructor: A function invoked when new instance is created to initialize its
contents. Multiple constructors with different sets of arguments can exist, for
user's convenience. Second convention regards to function called destructor,
which releases resources occupied by the instance; it is called just before the
instance itself is released. Finally, we will enforce all functions operating
on the Shape structure to receive pointer to the structure as their first argument and
every function will operate on that instance passed to it. Conventionally, such
pointer will be called "this" pointer, in order to emphasize its role.
We are ready to declare the desired functions. Note that all functions will
have Shape_ prefix added in order to prevent name collisions in the future.
void Shape_Constructor(struct Shape *_this);
void Shape_Constructor1(struct Shape *_this, float locationX, float locationY);
void Shape_SetName(struct Shape *_this, const char *name);
void Shape_PrintOut(struct Shape *_this);
void Shape_Destructor(struct Shape *_this);
Implementations of these functions are quite straightforward. We will place
them in shape.c file.
void Shape_Constructor(struct Shape *_this)
_this->locationX = 0.0F;
_this->locationY = 0.0F;
_this->name = keyword=NULL;
void Shape_Constructor1(struct Shape *_this, float locationX, float locationY)
_this->locationX = locationX;
_this->locationY = locationY;
_this->name = NULL;
void Shape_SetName(struct Shape *_this, const char *name)
if (_this->name != NULL)
_this->name = (char*)calloc(strlen(name) + 1, sizeof(char));
void Shape_PrintOut(struct Shape *_this)
if (_this->name != NULL)
printf("'s location is (%.2f, %.2f).\n", _this->locationX, _this->locationY);
void Shape_Destructor(struct Shape *_this)
if (_this->name != NULL)
Note that functions above are testing whether name pointer is null before accessing it. Note also that none of the functions is testing _this pointer before accessing it. This may look strange, but it has been done as a
convention. We are on the path of object-oriented programming, in which this pointer is guaranteed to be non-null, or otherwise function could not be
called in the first place. More on this topic will be said later. At this point
it is safe to assume that _this pointer, which is our custom implementation of C++ this pointer, is always
valid, i.e. non-null.
We are now ready to demonstrate use of the Shape structure.
int main(char args)
struct Shape *shape1 = NULL;
struct Shape *shape2 = NULL;
shape1 = (struct Shape*)malloc(sizeof(struct Shape));
Shape_Constructor1(shape1, 1.0F, 2.0F);
shape2 = (struct Shape*)malloc(sizeof(struct Shape));
Shape_Constructor1(shape2, 2.0F, 3.0F);
This code produces output:
Shape1's location is (1.00, 2.00).
Shape2's location is (2.00, 3.00).
Observe how clean and simple this code is. Reusability of the functions has
been employed in its finest. Even more important, which cannot be fully
recognized at this stage, is the fact that logic has been removed from the code
which calls it. For instance, we are not setting locationX and locationY of the shape directly - it is now done by the constructor in a way which is
suddenly becoming an operation of no special interest to us (as long as we are
happy with how the constructor does it). Even better illustration is setting
the shape's name, as it involves testing and reallocating dynamic memory.
Setting the name via the appropriate method, instead of directly manipulating
the name pointer from the structure is always the preferred way, even when we
are not keen to become object-oriented.
Upgrading Structure to Class
Object-oriented programming boils down to merging structure and functions
operating on that structure into one entity - a class. In its roots, class is a
structure with functions (now called methods). Off course, there is more than
that, but at this point it is sufficient to understand a class as a structure
In our shapes example this means that Shape structure will now be enriched with constructors, destructor, SetName and PrintOut methods. The way in which it is done in C++ programming language is
straight-forward. In the fresh C++ project we will first declare the class in a
header file. For convenience, we will name the header file shape.hpp so to avoid confusion with its C ancestor shape.h (in general, extension .h is also used in C++).
Shape(float locationX, float locationY);
void SetName(const char *name);
Note how similar declaration of the Shape class is to the contents of shape.h file in C. This class consists of three private fields (we will discuss
private and public keywords when time comes) - same fields as those in the
structure. It also exposes public methods (public means that methods can be
called from outside the class), which are one-to-one the same as functions
declared in C code. The only difference is that constructors are now named the
same as the class, and so is the destructor, only prefixed by the tilde (~)
sign. This is by convention and will always be so C++.
Now comes the implementation of Shape's methods, which is provided in the shape.cpp file.
#include #include <stdlib.h>
#include #include <string.h>
using namespace std;
locationX = 0.0F;
locationY = 0.0F;
name = NULL;
Shape::Shape(float locationX, float locationY)
this->locationX = locationX;
this->locationY = locationY;
name = NULL;
if (name != NULL)
void Shape::SetName(const char *name)
if (this->name != NULL)
this->name = new char[strlen(name) + 1];
cout << name << "'s location is (" << locationX << ", " << locationY << ")" << endl;
Once again, note how similar this file is to shape.c provided earlier in the C version of the code.
After Shape has been rewritten into class, main function also slightly changes as
presented in the following listing.
Shape *shape1 = new Shape(1.0F, 2.0F);
Shape *shape2 = new Shape(2.0F, 3.0F);
Note that methods are now called directly on the object. There is no reason to
call a global function in object-oriented language and then to pass it the
pointer to the object. This is because object itself is already associated with
its methods. When a method of one object is called, compiler is there to pass
pointer to that object into the method. In C++ this pointer serves the purpose
when accessing the object on which method was called.
Published: Jul 14, 2012; Modified: Jul 17, 2012
Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on design patterns, writing unit and integration tests and applying methods to improve code design and long-term maintainability.
Follow him on Twitter @zoranh75 to receive updates and links to new articles.
Watch Zoran's video courses at pluralsight.com (requires registration):
Tactical Design Patterns in .NET: Managing Responsibilities
Applying a design pattern to a real-world problem is not as straightforward as literature implicitly tells us. It is a more engaged process. This course gives an insight into tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More... p>
Tactical Design Patterns in .NET: Control Flow
Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More...
Improving Testability Through Design
This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More...
Share this article