Basic Example
We’re going to walk through the entire process of defining and using a
class in C++. In this example, we’ll create a Character class,
write its member function implementations, and then test our class in a
driver program. You’ll see how these components are organized into separate files:
-
character.h: Header file containing the class definition. -
character.cc: Source file where we implement the member functions. -
driver.cc: Driver file to test and demonstrate our class. -
makefile: A script that automates compiling and linking the program.
Step 1. Create Makefile
Section titled “Step 1. Create Makefile”Since we already know the names of our files, lets first create our makefile:
character.o : character.cc character.h g++ -Wall -std=c++17 -c character.cc
driver.o : driver.cc character.h g++ -Wall -std=c++17 -c driver.cc
driver: driver.o character.o g++ -Wall -std=c++17 driver.o character.o ./a.out
clean : rm *.o a.outStep 2. Create Header File
Section titled “Step 2. Create Header File”Next lets define our Character class in character.h. Don’t worry if you don’t
understand some of the code, we’ll be going over each section:
// Copyright 2024 CSCE240
#ifndef CHARACTER_H_#define CHARACTER_H_
#include <string>using std::string;
class Character { public: // Constructor name, hp, attack, defense explicit Character(string = "none", int = 0, int = 0, int = 0); // Copy Constructor Character(const Character&); // Destructor ~Character() { if (bag_ != nullptr) delete[] bag_; }
// Accessors string GetName() const { return name_; } int GetHp() const { return hp_; } int GetAtk() const { return attack_; } int GetDef() const { return defense_; }
// Mutators void SetName(string); void SetHp(int); void SetAtk(int); void SetDef(int);
// Utilities void AddToBag(string); void PrintBag() const;
private: string name_; int hp_; int attack_; int defense_;
int bag_capacity_; string* bag_; int current_bag_size;};
#endifData Members
Section titled “Data Members”Under the private accessor, we’ve added a couple of basic stats for our class along
with a pointer that acts like an inventory:
string name_;int hp_;int attack_;int defense_;
int bag_capacity_;string* bag_;int current_bag_size;Constructor
Section titled “Constructor”Our constructor uses default parameters, allowing objects to
be created with or without arguments. We’ve also declared it as explicit
to prevent unintended implicit conversions—specifically, creating a
Character object by assigning it a string (e.g., Character v = "Villain";).
Because one of the constructor’s parameters is a string, the explicit
keyword ensures an object is only constructed when we explicitly call the
constructor, rather than through an automatic type conversion:
// Constructor name, hp, attack, defenseexplicit Character(string = "none", int = 0, int = 0, int = 0);Copy Constructor
Section titled “Copy Constructor”The copy constructor is used when creating a new object by passing an existing object of the same class. In this class, we have a dynamic data member (a pointer), so it’s important to create a copy constructor that allocates new memory for the copy. Otherwise, multiple objects would end up sharing the same pointer and point to the same memory—leading to issues like double-deletion and data corruption:
// Copy ConstructorCharacter(const Character&);Destructor
Section titled “Destructor”Because our class contains a pointer data member, a destructor is needed
to properly release any dynamically allocated memory. In this example,
the destructor checks whether bag_ is pointing to an allocated array.
If so, it calls delete[] to free the memory. Since the implementation
is brief, we’ve included it directly in the header:
// Destructor~Character() { if (bag_ != nullptr) delete[] bag_;}Accessor Functions
Section titled “Accessor Functions”Just like the destructor, our Getter Functions contain very little code so we can write the implementation in the header file:
// Accessorsstring GetName() const { return name_; }int GetHp() const { return hp_; }int GetAtk() const { return attack_; }int GetDef() const { return defense_; }Mutator Functions
Section titled “Mutator Functions”Our Setter functions require a bit of conditional statements so we’ll usually only define them in the header file:
// Mutatorsvoid SetName(string);void SetHp(int);void SetAtk(int);void SetDef(int);Utility Functions
Section titled “Utility Functions”Since we have an inventory, we need to write a function to add items.
After adding items, we can write a function to print
the contents of the bag_:
// Utilitiesvoid AddToBag(string);void PrintBag() const;Step 3. Create Source File
Section titled “Step 3. Create Source File”Lets move to character.cc to write the implementation for our class. Instead
of feeding you the entire document, we’ll go over each section.
First we setup the document by importing what we need:
// Copyright 2024 CSCE240
#include "character.h"
#include <iostream>#include <string>
using std::cout;using std::endl;using std::string;Mutators
Section titled “Mutators”We’ll first write our mutators since we can use them in the constructor. They’re all pretty similar in requiring a simple condition:
// Mutatorsvoid Character::SetName(string n) { if (n != "") { name_ = n; } else { name_ = "none"; }}
void Character::SetHp(int h) { if (h > 0) { hp_ = h; } else { hp_ = 0; }}
void Character::SetAtk(int a) { if (a > 0) { attack_ = a; } else { attack_ = 0; }}
void Character::SetDef(int d) { if (d > 0) { defense_ = d; } else { defense_ = 0; }}Constructor
Section titled “Constructor”We can now use our mutators in the constructor to initialize some data members with any arguments passed. Any data member dealing with the Character’s inventory will be initialized manually:
// Constructor name, hp, attack, defenceCharacter::Character(string n, int h, int a, int d) { SetName(n); SetHp(h); SetAtk(a); SetDef(d);
bag_capacity_ = 5; bag_ = new string[bag_capacity_]; current_bag_size = 0;}Copy Constructor
Section titled “Copy Constructor”For the copy constructor, we assign most data members of the new class to the data members of the object’s data members. We then iterate to pass the contents of the inventory from one class to the new class:
// Copy ConstructorCharacter::Character(const Character& c) { name_ = c.name_; hp_ = c.hp_; attack_ = c.attack_; defense_ = c.defense_;
bag_capacity_ = c.bag_capacity_; current_bag_size = c.current_bag_size;
if (c.bag_ == nullptr) { bag_ = nullptr; // Handles cases where bag is NULL } else { bag_ = new string[bag_capacity_]; for (int i = 0; i < current_bag_size; ++i) { bag_[i] = c.bag_[i]; } }}AddToBag
Section titled “AddToBag”To add an item to our inventory, we first check to see that the passed value is not an empty
string and that our inventory is not full. We then assign it to an index and updated the size:
void Character::AddToBag(string item) { if (item == "" || current_bag_size == bag_capacity_) return;
bag_[current_bag_size] = item; ++current_bag_size;}To print our inventory we first check if the inventory is empty. Then if it contains items we iterate and print each element:
void Character::PrintBag() const { if (current_bag_size == 0) return;
for (int i = 0; i < current_bag_size; ++i) { cout << bag_[i] << endl; }}Step 4. Test
Section titled “Step 4. Test”Default Constructor
Section titled “Default Constructor”Finally we move to the driver file. Lets first check that our constructor works without any arguments. This will be the only time I’ll show the complete driver:
// Copyright 2024 CSCE240
#include <iostream>
#include "character.h"
using std::cout;using std::endl;
int main() { // Check Default Constructor cout << "Default Constructor Check" << endl; cout << "-------------------------" << endl; Character a; cout << "Name " << (a.GetName() == "none") << endl; cout << "HP " << (a.GetHp() == 0) << endl; cout << "Atk " << (a.GetAtk() == 0) << endl; cout << "Def " << (a.GetDef() == 0) << endl; cout << endl;
return 0;}make driverg++ -Wall -std=c++17 -c driver.ccg++ -Wall -std=c++17 -c character.ccg++ -Wall -std=c++17 driver.o character.o./a.outDefault Constructor Check-------------------------Name 1HP 1Atk 1Def 1Overloaded Constructor
Section titled “Overloaded Constructor”Next we’ll check to see that our constructor works when passing parameters. I’ll only show the results for the new tests instead of the entire output:
// Check Overloaded Constructorcout << "Overloaded Constructor Check" << endl;cout << "----------------------------" << endl;Character b("Zidane", 100, 40, 20);cout << "Name " << (b.GetName() == "Zidane") << endl;cout << "HP " << (b.GetHp() == 100) << endl;cout << "Atk " << (b.GetAtk() == 40) << endl;cout << "Def " << (b.GetDef() == 20) << endl;cout << endl;Overloaded Constructor Check----------------------------Name 1HP 1Atk 1Def 1Copy Constructor
Section titled “Copy Constructor”Now we’ll test the copy constructor by passing the previously made Character b object. We’ll alter the
data in the new Character c to make sure the contents in Character b are not altered:
// Check Copy Constructorcout << "Copy Constructor Check" << endl;cout << "----------------------" << endl;Character c(b);cout << "Same Name " << (c.GetName() == "Zidane") << endl;cout << "Same HP " << (c.GetHp() == 100) << endl;cout << "Same Atk " << (c.GetAtk() == 40) << endl;cout << "Same Def " << (c.GetDef() == 20) << endl;c.SetName("Vivi");c.SetHp(80);c.SetAtk(30);c.SetDef(15);cout << "Name Change " << (b.GetName() != c.GetName()) << endl;cout << "Hp Change " << (b.GetHp() != c.GetHp()) << endl;cout << "Atk Change " << (b.GetAtk() != c.GetAtk()) << endl;cout << "Def Change " << (b.GetDef() != c.GetDef()) << endl;cout << endl;Copy Constructor Check----------------------Same Name 1Same HP 1Same Atk 1Same Def 1Name Change 1Hp Change 1Atk Change 1Def Change 1Inventory
Section titled “Inventory”Finally we test our inventory system. We’ll add some items, then test that our conditional
statement is working by trying to pass an empty string, and by trying to add an item when the
inventory is full:
// Bag Checkcout << "Bag Check" << endl;cout << "---------" << endl;a.AddToBag("sword");a.AddToBag("rod");a.AddToBag("potion");a.AddToBag("special pendant");a.AddToBag(""); // should not adda.AddToBag("running shoes");a.AddToBag("should not add"); // should not add, reached capacity limita.PrintBag();Bag Check---------swordrodpotionspecial pendantrunning shoes