Delving into C++

As mentioned previously, a prerequisite of the CG Spectrum Game Programming Foundations course is a basic understanding of the C++ programming language.
My programming experience has mostly been with higher-level languages. I started with Visual Basic before moving on to Java and then C#.
Of those, I’ve always found C# particularly intuitive, but I’ve also wanted to learn C++ for a long time.
Since I already had a solid understanding of the core principles, I saw little value in taking extensive notes on concepts I was already familiar with, and instead committed code to:
sawnoff-studios/game-programming-foundations
This also gives me a practical reference to return to, while letting me track my progress through the course.
Topics
The topics studied over those 12 weeks were:
- Game Programming Concepts
- Variables and Operators
- Conditionals
- Loops
- Functions
- Classes and Objects
- Pointers, References & Dynamic Memory
- Arrays
- Inheritance & Polymorphism
- Templates
- Game Loop
- Putting It All Together
This was followed by using the PlayBuffer library to practise implementing the concepts learned, committed to sawnoff-studios/playbuffer.
Through this I gained a deeper understanding of how to use C++ to create games, with cppreference.com and GeeksforGeeks proving invaluable.
Differences
While primitive types such as int, float and bool are similar to their C# counterparts, there are key differences in the standard library data structures – for me mostly in the naming rather than the implementation:
| C++ | C# equivalent | Description |
|---|---|---|
std::vector | List<T> | Dynamic, resizable array |
std::list | LinkedList<T> | Doubly linked list |
std::string | String | String class |
std::map | Dictionary<TKey, TValue> | Stores key/value pairs |
std::deque | (no direct equivalent) | Double-ended queue |
References vs Pointers
One of the main differences between references and pointers in C++ is how they handle nullability, reassignment, syntax, memory management, and flexibility.
In managed languages such as C# and Java, garbage collection handles memory automatically; in C++, memory management is manual and requires the new and delete operators.
| Feature | References | Pointers |
|---|---|---|
| Nullability | Cannot be null | Can be null (nullptr) |
| Reassignment | Cannot be reassigned | Can be reassigned |
| Syntax | Simple, no dereferencing | Requires * or -> |
| Memory management | No manual management | Requires new/delete for heap data |
| Flexibility | Tied to one object for its lifetime | Can point to different objects |
Recap Thoughts
Code is spread out a lot across files.
Coming from higher-level languages, it felt like a pain switching between the .h file to define class members and the .cpp file to implement them. I started seeing .h files as the ‘interface’ to a class, which is different to what I’m used to.
It’s a bit of a hassle, but a necessary evil – otherwise, I found C++ remarkably similar to C#.
Alternate constructor syntax is weird.
In C#, constructors look like this:
public class Person
{
private string _name;
private int _age;
public Person(string name, int age)
{
_name = name;
_age = age;
}
}Whereas C++ initialises members in an initialiser list - with the members defined in the .h file, then assigned via what looks like a method call in the .cpp:
// Person.h
class Person
{
std::string m_name;
int m_age;
public:
Person();
Person(std::string name, int age);
};// Person.cpp
#include "Person.h"
Person::Person()
: m_name("Unnamed")
, m_age(0)
{
}
Person::Person(std::string name, int age)
: m_name(name)
, m_age(age)
{
}Friend is a scary concept.
The friend keyword grants a class access to another class’s private and protected members, breaking encapsulation.
In the course example, two classes were defined - Spiderman and Venom - with Venom declared a friend of Spiderman, allowing Venom::AccessSpidermanHealth() to modify Spiderman’s health without inheritance.
I found it a bit of a scary concept – no such thing exists in C# without compiler workarounds.
// Spiderman.h
#pragma once
#include <string>
class Venom; // Forward declaration
class Spiderman
{
friend class Venom;
public:
Spiderman();
Spiderman(int inHealth);
private:
std::string name;
int health;
};// Venom.h
#pragma once
#include "Spiderman.h"
class Venom
{
public:
Venom();
Venom(int inHealth);
void AccessSpidermanHealth();
private:
Spiderman spiderman;
};// Venom.cpp
#include <iostream>
#include "Venom.h"
Venom::Venom() : Venom(0)
{
}
Venom::Venom(int inHealth)
{
spiderman.health = inHealth; // Legal only because of the friend declaration
}
void Venom::AccessSpidermanHealth()
{
std::cout << "Accessing Spiderman health " << spiderman.health << '\n';
}Forward declarations are interesting.
In higher-level languages, you define a class and it can instantly be referenced elsewhere.
In C++, forward declarations let you declare a type’s existence ‘ahead of time’ for the compiler:
// Player.h
class Enemy; // Forward declaration
class Player
{
public:
static void PlayerTurn(Player& player, std::vector<Enemy>& enemies);
static void PlayerAttack(Player& player, Enemy& enemy);
};// Enemy.h
#include "Player.h"
class Enemy
{
public:
static void EnemyTurn(Player& player, Enemy& enemy);
static void EnemyAttack(Player& player, Enemy& enemy);
};Here, Player.h references Enemy, but adding #include "Enemy.h" to Player.h would create a circular reference – each header including the other, a chicken-and-egg situation. Forward-declaring Enemy in Player.h and including the full header only where needed breaks the cycle.
The second benefit is compile times: an #include in a .h file pulls in everything from that file, including its own includes - pages and pages of code that need compiling. Forward declarations only reference what’s required.
Operator overloading can be useful.
Another scary-seeming concept: overloading existing operators such as +, == and = for custom types. It makes for intuitive, readable code, but can cause confusion if misused:
#pragma once
class Position
{
public:
Position();
Position(float inX, float inY);
~Position();
Position operator+(const Position& other) const
{
return Position(X + other.X, Y + other.Y);
}
bool operator==(const Position& other) const
{
return ((X == other.X) && (Y == other.Y));
}
Position& operator=(const Position& other)
{
X = other.X;
Y = other.Y;
return *this;
}
private:
float X;
float Y;
};Three overloaded operators - +, == and = - allowing Positions to be added, compared, and assigned:
Position pos1(1.0f, 2.0f);
Position pos2(3.0f, 4.0f);
Position pos3 = pos1 + pos2; // pos3.X = 4.0f, pos3.Y = 6.0f
bool areEqual = (pos1 == pos2); // false
pos1 = pos2; // pos1.X = 3.0f, pos1.Y = 4.0f
Pointers aren’t that scary.
Pointers aren’t really a concept in higher-level languages, but they’re fundamental to C++. I’d always been a bit scared of them – I’d heard they can have unintended consequences – but they’re simple once you get the hang of them.
In the course example, a Car struct is allocated on the heap via a pointer, and its members accessed through the dereference operator (->):
#include <iostream>
using namespace std;
int main()
{
struct Car
{
string make;
string model;
int year;
};
Car* car = new Car();
cout << "Enter the car's make\n";
cin >> car->make;
cout << "Enter the car's model\n";
cin >> car->model;
cout << "Enter the car's year\n";
cin >> car->year;
cout << "You entered " << car->year << " " << car->make << " " << car->model;
delete car; // Don't leak!
return 0;
}References are interesting.
Following on from pointers, references were equally interesting – they act as an alias for an existing variable:
#include <iostream>
using namespace std;
int main()
{
int x = 10;
int& ref = x; // ref is a reference (alias) to x
cout << ref << endl; // Prints 10
ref = 22; // Writing through ref modifies x itself
cout << ref << endl; // Prints 22
cout << x << endl; // Prints 22 - x and ref are the same object
return 0;
}Certificate
After three months of study, I officially passed this module and received my certificate on 26th June 2025.
Many thanks to Cameron Cintron for your support and encouragement throughout this part of my journey!
Onwards towards learning Unreal Engine!
Related Posts
2025-02-28
2024-10-24
2024-08-30
