# Step 2: Writing C++ Classes¶

Read time: 22 minutes (5722 words)

Let’s add our first class, for something called the “Machine”:

Create a new folder in your project. Name this one include. Place this file in this new directory.

include/Machine.h
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Copyright 2018 Roie R. Black #pragma once #include class Machine { public: // constructor explicit Machine(std::string n); // accessors std::string get_name(void); private: std::string name; }; 

All classes are named starting with a capital letter. This is a convention, not a law.

## Writing C++ classes¶

The C++ compiler does not really care about how you lay out a C++ project. All it cares about is that you tell it where you hid your files. However, it is an extremely bad idea to write code without having a solid style that you follow every time you craft a program file.

In this class, all C++ class code will be split into two parts: a header file that lays out the class definition, but contains as little code as possible (ideally none at all). The second file will be the implementation file, with all the real code to make the class complete. That implementation file goes in a folder named lib.

The name of the header file is that class name followed by a .h. (In some circles, you might use .hpp. We will not do that in our code.) The implementation file has the same name again, this time with a .cpp extension. (Occasionally, I see .cxx, but that is rare.)

Formally, that header file is a public document, needed by both developers who use your class, and developers who implement that class. Users have no real business looking into how you implement a class. The header file tells them all they need to know to use the class. As long as you honor the “contract” specified in this header, you are free to think up completely new implementations, hopefully that make the class a better piece of code.

With this header in hand, let’s think through how we might test it.

Here is the implementation file:

lib/Machine.cpp
  1 2 3 4 5 6 7 8 9 10 11 12 // Copyright 2019 Roie R. Black #include #include "Machine.h" Machine::Machine(std::string n) { name = n; } std::string Machine::get_name(void) { return name; } 

## Testing a Class¶

C++ classes define a set of attributes and a set of methods. The attributes represent a kind of “state” that objects created with the class will set up. The methods provide a way to manipulate that state, or examine that state. We definitely need to check to see that each method does what it is supposed to do. Sometimes, that is easy, sometimes, you need to get creative to test things.

### Class Constructor¶

Every class has a constructor, although you may not have written it. We will provide one and ask that that code set up default values for all attributes defined in the class. For the Machine class, all we have that we could test is that machine name string we will provide on the constructor. Maybe a simple tests just sets the name and verifies that it is stored correctly. I am going to use a simple pattern for naming methods in this class. Any method that sets an attribute will have a name beginning with the string set_, and any method that fetches an attribute will be named with get_. I am definitely not just allowing anyone to access attributes. The default for all of them is private unless you have a really good reason for making them public!

## Writing Our First Test¶

We are ready to create a test. Wait! We have no code to test. That is perfect. We need to think through when we want to see happen when we write the code, and come up with a way to verify that the code works as expected. At this point, all I have is a constructor. That constructor is going to take a name string as a parameter, and store it away for later reference. The single method we have defined will fetch the recorded name later.

What about setting the name. That does not make sense in this situation. We will only create one machine in our simulator. (Hmmm, maybe I could create more if I want to simulate parallel processing. That might be something for later!) We will not let folks change the name once it is set!

That leaves the accessor routine. We can ytest our contructor if we simple return the string, and check that it matches the name we handed to the constructor. The test is a simple logical expression.

Sounds easy to write, let’s see this in action!

## Setting up Catch¶

Catch is a single header file system that sets up unit testing in a C++ project. All you need to do is add the heder file to your project, then write a few short files.

### Clone Catch¶

The Catch project code is on GitHub (naturally!) In your course folder (not in another repo), do this:

$cd cosc2325$ git clone https://github.com/catchorg/Catch2.git


Inside of this project you will find a single file that you need to copy into your project folder:

$cp Catch2/single_include/catch2/catch.hpp cpu-factory/include  We need to modify our Makefile so it will do testing for us. Here is the new version: Makefile   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 TARGET = demo TSTAPP = testapp SSRCS =$(wildcard src/*.cpp) LSRCS = $(wildcard lib/*.cpp) LOBJS =$(LSRCS:.cpp=.o) TSRCS = $(wildcard tests/*.cpp) APPOBJS =$(SSRCS:.cpp=.o) $(LOBJS) TSTOBJS =$(TSRCS:.cpp=.o) $(LOBJS) CFLAGS = -I include -std=c++11 .PHONY: all all:$(TARGET) $(TARGET):$(APPOBJS) g++ -o $@$^ $(TSTAPP):$(TSTOBJS) g++ -o $@$^ .PHONY: clean clean: rm -f $(TARGET)$(TSTAPP) $(APPOBJS)$(TSTOBJS) %.o: %.cpp g++ -c $(CFLAGS) -o$@ $< .PHONY: run run:$(TARGET) ./$(TARGET) .PHONY: test test:$(TSTAPP) ./$(TSTAPP)  ### Configure for Testing¶ Catch is designed in such a way that you create a new application in your project, and this one runs tests. To make all of that happen, we added a few rules to the Makefile and we need a simple file to create the main function for the test application. Here is the file you need. Just drop it in the tests folder and forget about it! tests/test_main.cpp  1 2 3 4 // COpyright 2018 Roie R. Black #define CATCH_CONFIG_MAIN #include  The contents of this file just tell the header that it needs to add a main function here. The pattern for a test is shown in the next file. I like adding this to a new project. The only reason for this file is for testing the test system. With no real tests around, at ;east I can see that the test application gets built, and that tests run successfully! Here is the sanity test: tests/test_sanity.cpp  1 2 3 4 5 6 // Copyright 2018 ROie R. Black #include TEST_CASE( "sanity test", "sanity" ){ REQUIRE(true); }  Look at the line with TEST_CASE on it. The two strings are used to identify the test, and name a test group that could be used to isolate testing to one area of the code. This is not something we need to worry about now, but it might come in handy later. Let’s try this out! $ make clean
rm -f demo testapp src/main.o lib/Machine.o tests/test_main.o tests/test_sanity.o lib/Machine.o

$make g++ -c -I include -std=c++11 -o src/main.o src/main.cpp g++ -c -I include -std=c++11 -o lib/Machine.o lib/Machine.cpp g++ -o demo src/main.o lib/Machine.o  $ make test
g++ -c -I include -std=c++11 -o tests/test_main.o tests/test_main.cpp
g++ -c -I include -std=c++11 -o tests/test_sanity.o tests/test_sanity.cpp
g++ -o testapp tests/test_main.o tests/test_sanity.o lib/Machine.o
./testapp
===============================================================================
All tests passed (1 assertion in 1 test case)


That last line above is what we want to see. We had one real (well almost real) test in our test code. The test checked that it worked properly, and it did!

We have made some progress, even though we do not have much real code yet. You now have a basic project structure that will survive a good part of our coding, and we have a unit test system running to help test our code.

There is one more step I want to take before we launch off and create real code.

That step will stop any lingering “smell” in your code!