Lesson 2 - First OOP application in C++ - Hello object world
At the beginning of the Basic C++ constructs course we created a Hello world program. Let's do a similar program as an introduction to object-oriented programming. We'll program Hello object world!
Creating a project
First, we'll create a new project (console application). You can see how to create the project in the screenshots below.
We create the project as a classic empty application. Then we click on OK:
In the project, we'll create a new main.cpp
file. We'll do it by
right-clicking the project in Solution Explorer and choosing Add -> New
Item:
Then we select the .cpp
file:
In this file, we'll will insert the basic C++ application structure as we have been used to:
#include <iostream> using namespace std; int main() { return 0; }
In Solution Explorer, we'll right-click the Source files folder and select Add -> Class:
In the window that appears, we'll click on C++ Class. Then a next window is displayed, in which we fill in the names as shown. These are names of the class files that will represent a pattern to create objects which can greet:
Visual Studio creates two files for us: Zdravic.h
(there will be
the class itself) and Zdravic.cpp
(where the function definitions
will be). The division of the class into these two files is necessary - see C
and C++ compilation lessons. We'll rewrite the contents of the files to:
Greeter.h
#ifndef __GREETER_H__ #define __GREEER_H__ class Greeter { }; #endif
Greeter.cpp
#include "Greeter.h"
The preprocessor directives (#ifndef
,#define
, and
#endif
) ensure that the file is included only once. By default,
Visual Studio uses the #pragma once
directive, but this one is more
practical for us (it works even when compiling on Linux). The originally
generated Greeter(void)
and ~Greeter(void)
functions
were a constructor and a destructor that we'll look at in the next lesson.
Method declaration
When we'll use this class, we'll want it to do something. That's why we're
going to provide some methods in the Greeter
class. In C++, we
write methods the same as functions:
Greeter.h
#ifndef __GREETER_H__ #define __GREETER_H__ class Greeter { public: void greet(); }; #endif
Greeter.cpp
#include <iostream> #include "Greeter.h" using namespace std; void Greeter::greet(void) { cout << "Hello object world!"; }
We must declare the method twice, once as a header in the .h
file and once with the body in the .cpp
file. Here we have finished
for now, let's move to main.cpp
.
Creating a class instance
Now, we're goint to create a Greeter
instance in the body of the
main()
method. But first we have to say that we want to use our
Greeter
class, which we've just created. We do this by including
our class in the main.cpp
file using
#include "Greeter.h"
. Unlike classic include (for example of
iostream
), you may notice replacing angle brackets with quotes. If
we use brackets, the compiler searches for the file in its paths (typically
library paths). If we use quotes, the compiler will use the relative path (the
current project folder in our case).
We store objects in variables, the class name is used as the data type (same
as int
, for example). We'll declare a variable and then create a
new instance of Greeter
in it:
#include <iostream> #include "Greeter.h" using namespace std; int main() { Greeter _greeter; return 0; }
This creates a variable _greeter
. We can also create an instance
as follows:
Greeter* _greeter = new Greeter();
[here]
This approach creates an instance dynamically and it's stored on the heap. We'll return to it in more advanced parts of our C++ course.
Calling the method
And because we already have our first object (instance), we can call its
method. At the end of the code (before return 0;
), we'll add
cin.get()
(so that the program doesn't end immediately and wait for
any key to be pressed). Finally, the main.cpp
file looks like
this:
main.cpp
#include <iostream> #include "Greeter.h" using namespace std; int main() { Greeter _greeter; _greeter.greet(); cin.get(); return 0; }
Now we can run the program. The output will be as follows:
Console application
Hello object world!
So we have our first object-oriented application! The logic is performed by a corresponding object. When we write larger applications, we'll appreciate such decomposition of functions into individual objects since the resulting application is very clear.
Method parameters
Now let's give our greeting()
method a name
parameter to greet a particular user:
Greeting.h
#ifndef __GREETER_H__ #define __GREETER_H__ #include <string> using namespace std; class Greeter { public: void greet(string name); }; #endif
Greeter.cpp
#include <iostream> #include "Greeter.h" using namespace std; void Greeter::greet(string name) { cout << "Hi " << name << endl; }
Now let's update our main()
function:
Greeter _greeter; _greeter.greet("Carl"); _greeter.greet("Peter");
And after running the application, we get the following output:
Console application
Hi Carl
Hi Peter
Class attributes
Let's add some field (variable) to the class, e.g. a text where the greeting will be stored. From the previous lesson, we already know that classes contain functions and data. We declare data parts of classes the same as variables. Here's what our class should look like at this point.
Greeter.h
We declare the field in the header file:
class Greeter { public: string text; void greet(string name); };
Now all Greeter
instances store their text.
Greeter.cpp
We'll edit the greeting()
method to greet using the text in the
text
field:
void Greeter::greet(string name) { cout << text << " " << name << endl; }
main.cpp
Now we need to set up the instance we created in main.cpp
for
the first time:
Greeter _greeter; _greeter.text = "Hi"; _greeter.greet("Carl"); _greeter.greet("Peter"); _greeter.text = "Hello programmer"; _greeter.greet("Richard");
And the application's output:
Console application
Hi Carl
Hi Peter
Hello programmer Richard
Method return value
In object-oriented design, it's not recommended to let each object control
the input and output, i.e. printing lots of stuff into the console. Each object
should have a single responsibility and shouldn't exceed its purpose. Let's make
our object solely responsible for creating the greeting text, and we'll move the
printing outside the object, i.e. to the main()
method. The
advantage to designing objects with a single responsibility is that they're then
universal and reusable. Our object can only print text to the console now, but
we'll change it so the method will only return the text and it'll be up to the
recipient to decide what to do with it. Like this we could store greetings into
files, print them on websites or process them further.
Since we want the method to return a string
value, we change its
void
type to string
. To return a value, we use the
return
command. Let's edit the class code:
Greeter.h
class Greeter { public: string text; string greet(string name); };
Greeter.cpp
And so is the implementation:
string Greeter::greet(string name) { return text + " " + name + "!\n"; }
main.cpp
To do this, we need to edit the main.cpp
file:
int main() { Greeter _greeter; _greeter.text = "Hi"; cout << _greeter.greet("Carl"); cout << _greeter.greet("Peter"); _greeter.text = "Hello programmer"; cout << _greeter.greet("Richard"); cin.get(); return 0; }
Our code now meets best practices. The source codes are included below the article. You can try the whole program here or in the attached project.
#include <iostream> #include "Greeter.h" using namespace std; int main() { Greeter _greeter; _greeter.text = "Hi"; cout << _greeter.greet("Carl"); cout << _greeter.greet("Peter"); _greeter.text = "Hello programmer"; cout << _greeter.greet("Richard"); cin.get(); return 0; }
#ifndef __GREETER_H__ #define __GREEER_H__ #include <string> using namespace std; class Greeter { public: string text; string greet(string name); }; #endif
#include <iostream> #include "Greeter.h" string Greeter::greet(string name) { return text + " " + name + "!\n"; }
Great! Our program already has some quality to it, despite it being relatively useless. If you want, you can try to create an object-oriented remake of our console calculator. Next time, A RollingDie in C++ and Constructors, we'll take a closer look at the promised constructors and destructors.
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
Download
By downloading the following file, you agree to the license terms
Downloaded 11x (386.16 kB)
Application includes source codes in language C++