Robert Johns | 16 Jan, 2024
Fact checked by Jim Markus

Want To Level-Up Your C++? Build These C++ Projects!

 

In this article, I share the 10 best C++ projects for beginners in 2024 with full source code.

Whether you’re looking to land a job as a systems developer or enhance your portfolio, these C++ projects are ideal for leveling up your skills.

I’ve also designed these C++ projects to be more challenging as you make your way through them, meaning this is a lot like taking a free C++ course!

With a history spanning nearly three decades, C++ is a versatile, high-performance language that’s popular for systems, software, and game development. It’s no wonder it’s still a top 10 language among developers.

Plus, with the Bureau of Labor Statistics reporting an average salary of more than $100K for programmers, building C++ projects can be very lucrative for your career.

So, if you’re ready, let’s dive into and start building these C++ projects!

10 Best C++ Projects For Beginners

Alright! So you’ve installed your C++ compiler, you’ve set yourself up in VSCode or your other favorite C++ IDE, and now it’s time to get building!

If you’re new to the C++ programming language, this is the best place to start!

It doesn’t matter whether your motivation is to use C++ as a language for game development or you’d like to help build the next iteration of Photoshop; you will need C++ basics.

But we’ll be going much further than that!

Yep, we’ll be building ten C++ projects for beginners, each designed to get slightly more challenging as you work through the list.

In lots of ways, this is a lot taking a C++ course, as I’ll be layering in new C++ skills with each successive project.

I really like this approach, as it lets you stack your C++ skills in a natural and progressive way, much like you would during a college class.

So grab your C++ cheat sheet, and get ready to stretch yourself! Let’s dive into these beginner projects!

1. Classic Hello, World!

When it comes to C++ project ideas, this has to be the grandfather of them all!

Okay, okay, if you already know a little C++, you might want to skip past this project, but if you’re brand new to C++ syntax, you have to get started with the classic ‘Hello, world!’ program.

It’s almost like a rite of passage for every C++ newbie, not to mention an homage to our programming forefathers!

As this is the quintessential beginner program, I’ll also remind you to save your C++ program files with a .cpp extension. 

C++ Source Code:

#include <iostream> // Includes the IO stream library

int main()
{
  std::cout << "Hello, World!" << std::endl;
  // Prints "Hello, World!" to the console
 
  return 0;                                
  // Indicates that the program ended successfully
}

Code Explanation:

So, what’s happening in this simple C++ program? Let’s break down the various parts:

  1. #include <iostream>: Here, we include the IO stream library to access the definitions for input/output operations.
  2. int main() { ... }: This is the main function where the execution of your C++ program begins.
  3. std::cout << "Hello, World!" << std::endl;: This is where we output the text "Hello, World!" followed by a new line.
  4. return 0;: This ends the main function and returns 0, signaling a successful run.

Does that all make sense?

Now, when you compile this code, you’ll have a fully functional program that prints "Hello, World!" to your console.

If you’re using VSCode, this should all happen within your coding environment. But you can also use the command line to compile the code if you’d prefer.

Awesome! This is a great first step into the world of C++ programming! Now, let’s work through the rest of these C++ projects and ramp up the difficulty at each stage.

Are you ready?

2. Calculator

I really like this C++ project for beginners, not only because we all know what a calculator is, but because it introduces user input, basic arithmetic operations, and conditional statements. 

When I was first starting out with C++, this was one of the first projects I built because it’s a great way to learn these foundational elements of C++ programming.

Bear in mind that this was also before Python and other high-level languages were popular, and I was just a fresh-faced coder eager to learn C++. 

Anyway, enough of that trip down memory lane, let’s get building.

C++ Source Code:

#include <iostream>

int main()
{
  double num1, num2;
  char operation;

  std::cout << "Enter first number: ";
  std::cin >> num1;

  std::cout << "Enter second number: ";
  std::cin >> num2;

  std::cout << "Enter an operation (+, -, *, /): ";
  std::cin >> operation;

  switch (operation)
  {
  case '+':
      std::cout << "Result: " << num1 + num2 << std::endl;
      break;
  case '-':
      std::cout << "Result: " << num1 - num2 << std::endl;
      break;
  case '*':
      std::cout << "Result: " << num1 * num2 << std::endl;
      break;
  case '/':
      if (num2 != 0)
      {
          std::cout << "Result: " << num1 / num2 << std::endl;
      }
      else
      {
          std::cout << "Error: Division by zero" << std::endl;
      }
      break;
  default:
      std::cout << "Invalid operation" << std::endl;
  }

  return 0;
}

Code Explanation:

So, what is happening in this C++ program? If you’ve spent any time reading C++ books or learning the language basics, you should be able to follow along quite easily.

Let’s break the code into its main parts:

  1. #include <iostream>: Includes the IO stream library for input and output operations.
  2. double num1, num2; char operation;: Declares two double variables for numbers and a char variable for the math operation.
  3. std::cin >> num1;, std::cin >> num2;, std::cin >> operation;: Takes input from the user for the numbers and the arithmetic operation.
  4. switch (operation) { ... }: These decision-making statements execute different code blocks based on the operation entered.
  5. case statements: Arithmetic operations are performed inside these.
  6. num2! = 0:  Check for division by zero to avoid errors.
  7. return 0;: Indicates successful program termination.

Hopefully, that all made sense, and you were able to follow along with the logic.

Now, when you run this C++ program, it will prompt you to input two numbers before asking you to choose an arithmetic operation. 

After providing the inputs, the program will display the result of the operation. 

Overall, this basic calculator project is a great way to understand user input and basic arithmetic in C++.

I’d also encourage you to make as many changes as you like to this project. 

In fact, I’d strongly recommend you make changes to see how they affect the output in your program.

In my opinion, this is one of the best ways to cement your C++ skills, as there’s no substitute for making changes and seeing what they do!

3. Number Guessing Game

Time for a new project! And it’s the Number Guessing Game – a classic C++ project to keep your C++ journey interesting! 

This C++ project is not only fun but also an excellent way to dive into new concepts like random number generation and more complex conditional logic. 

You’ll also see that this project steps up from the basic calculator we just built by introducing control flow with loops, alongside more user interaction to build on your previous skills. 

Now don’t get me wrong, this is a far cry from the AAA games you might want to build with C++ using something like Unreal Engine

But the path to creating those games is gaining foundational C++ skills! 

C++ Source Code:

#include <iostream>
#include <cstdlib> // For rand() and srand()
#include <ctime>   // For the time() function

int main()
{
  // Initialize random seed
  srand(static_cast<unsigned int>(time(0)));

  // Generate a random number between 1 and 100
  int secretNumber = rand() % 100 + 1;
  int guess = 0;

  std::cout << "I have chosen a number between 1 and 100." << std::endl;
  std::cout << "Can you guess what it is?" << std::endl;

  while (guess != secretNumber)
  {
      std::cout << "Enter your guess: ";
      std::cin >> guess;

      if (guess > secretNumber)
      {
          std::cout << "Too high! Try again." << std::endl;
      }
      else if (guess < secretNumber)
      {
          std::cout << "Too low! Try again." << std::endl;
      }
      else
      {
          std::cout << "Congratulations! You guessed my number!" << std::endl;
      }
  }

  return 0;
}

Code Explanation:

So, what’s going on with this C++ project? Let’s break the code down:

  1. #include <cstdlib> and #include <ctime>: We need these for using the rand(), srand(), and time() functions.
  2. srand(static_cast<unsigned int>(time(0)));: Initializes a random number generator with the current time as the seed value.
  3. int secretNumber = rand() % 100 + 1;: Generates a random number between 1 and 100.
  4. while loop: This keeps running until the user guesses the correct number.
  5. Loop body: The program takes the user's guess and compares it with the secret number, providing hints of whether they are too low or too high.

Now, when you run this C++ program, it will ask you to guess a number to see whether it matches the randomly generated value. 

Based on your guess, it will give you hints until you guess it correctly. 

I really like this game, as it’s an excellent way to understand control structures and random number generation in C++.

As always, feel free to make as many changes as you want with this project. Maybe you want to get really wild and use floating-point numbers? 

4. To-Do List

Moving on to project number four, we’re now going to build a To-Do List in C++. 

I really like this C++ project as it’s a step into the real world since you’ll be building a tool you can actually use every day! 

Expect to get to grips with file handling and basic data management, not to mention a practical introduction to managing and persisting data, as we’ll be saving our to-do items to a text file.

These are foundational skills for any C++ programmer, and it’s the ideal time to move from simple output to storing data persistently. 

It's like moving from learning vocabulary to writing stories in the language of C++!

C++ Source Code:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

void showTasks(const std::vector<std::string> &tasks)
{
  std::cout << "To-Do List:" << std::endl;
  for (int i = 0; i < tasks.size(); ++i)
  {
      std::cout << i + 1 << ". " << tasks[i] << std::endl;
  }
}

int main()
{
  std::vector<std::string> tasks;
  std::string task;
  char choice;

  // Load existing tasks from file
  std::ifstream inputFile("tasks.txt");
  while (getline(inputFile, task))
  {
      tasks.push_back(task);
  }
  inputFile.close();

  do
  {
      std::cout << "A - Add a task" << std::endl;
      std::cout << "V - View tasks" << std::endl;
      std::cout << "Q - Quit" << std::endl;
      std::cout << "Enter your choice: ";
      std::cin >> choice;

      switch (choice)
      {
      case 'A':
      case 'a':
          std::cout << "Enter a task: ";
          std::cin.ignore(); // Clears the input buffer
          getline(std::cin, task);
          tasks.push_back(task);
          break;
      case 'V':
      case 'v':
          showTasks(tasks);
          break;
      }
  } while (choice != 'Q' && choice != 'q');

  // Save tasks to file
  std::ofstream outputFile("tasks.txt");
  for (const auto &t : tasks)
  {
      outputFile << t << std::endl;
  }
  outputFile.close();

  return 0;
}

Code Explanation:

Let’s follow the same drill and break down the main parts of this C++ project to understand what’s happening:

  1. The program starts by including the necessary headers for file and string handling and the vector container.
  2. The showTasks function is used to display the current tasks.
  3. The main function reads existing tasks from a file, tasks.txt, into a vector.
  4. The user is prompted to add a task or view the current tasks.
  5. New tasks entered by the user are added to the vector.
  6. When the user quits, tasks are written back to tasks.txt, saving them for future sessions.

When you run this program, you’ll see a simple user interface that allows you to add tasks to your to-do list or view the current list.

We’ve also included an option to quit the program, which results in your tasks being saved to a text file. 

Overall, this C++ project is great for getting to grips with basic file operations, dynamic data handling using vectors, and simple program flow control in C++.

How would you alter this C++ program? Maybe you can add some more fields, like dates and times for to-dos? Perhaps you could even investigate a search function that uses keywords?

Get creative, as that’s the best way to flex your C++ programming muscles while also cementing these new skills.

5. Temperature Converter App

The next C++ project on our list is a temperature converter app that’s also a great way to get to grips with functions in C++. 

At this stage in our list of C++ projects, it made sense to me to ramp up the complexity of our C++ programs, and functions are a great way to do this.

If you want to write good C++ programs, functions will be essential for organizing your code and implementing basic D.R.Y principles. 

We’ll also be using more complex mathematical operations by converting temperatures between Fahrenheit, Celsius, and Kelvin.

Let's check out how to build this temperature conversion app.

C++ Source Code:

#include <iostream>

double CelsiusToFahrenheit(double celsius)
{
  return (celsius * 9.0 / 5.0) + 32.0;
}

double FahrenheitToCelsius(double fahrenheit)
{
  return (fahrenheit - 32.0) * 5.0 / 9.0;
}

double CelsiusToKelvin(double celsius)
{
  return celsius + 273.15;
}

double KelvinToCelsius(double kelvin)
{
  return kelvin - 273.15;
}

int main()
{
  int choice;
  double temperature, convertedTemperature;

  std::cout << "Temperature Converter" << std::endl;
  std::cout << "1. Celsius to Fahrenheit" << std::endl;
  std::cout << "2. Fahrenheit to Celsius" << std::endl;
  std::cout << "3. Celsius to Kelvin" << std::endl;
  std::cout << "4. Kelvin to Celsius" << std::endl;
  std::cout << "Enter your choice (1-4): ";
  std::cin >> choice;

  std::cout << "Enter the temperature: ";
  std::cin >> temperature;

  switch (choice)
  {
  case 1:
      convertedTemperature = CelsiusToFahrenheit(temperature);
      break;
  case 2:
      convertedTemperature = FahrenheitToCelsius(temperature);
      break;
  case 3:
      convertedTemperature = CelsiusToKelvin(temperature);
      break;
  case 4:
      convertedTemperature = KelvinToCelsius(temperature);
      break;
  default:
      std::cout << "Invalid choice." << std::endl;
      return 1;
  }

  std::cout << "Converted Temperature: " << convertedTemperature << std::endl;

  return 0;
}

Code Explanation:

Now we’ve created this C++ project, let’s review the main components of the program:

  1. We included the iostream header for input and output.
  2. We defined four conversion functions for: CelsiusToFahrenheit, FahrenheitToCelsius, CelsiusToKelvin, KelvinToCelsius
  3. The main function displays a menu for the user to choose the type of conversion.
  4. The user is prompted to enter the temperature value, and based on the choice, the corresponding conversion function is called.
  5. The switch statement handles the user's choice and performs the appropriate conversion.
  6. The converted temperature is then displayed to the user.

When you run this program, you’ll see a simple user interface that allows the user to input a temperature and select the type of conversion they wish to perform. 

Based on the selected choice, the program will output the converted temperature. 

I really like this C++ project because it provides a gentle introduction to functions while also extending our use of user input and arithmetic operations in C++.

How else could you expand this program? Maybe you could add sub-menus for different types of conversion? 

For example, you could add the option to toggle between temperature and pressure conversion. How would you do this? 

Hint: you’ll need an additional layer of conditional logic and new conversion functions.

6. Bank Management System

Next up, we’ll dive into financial management with a simple Bank System that lets users create an account with a basic registration system, not to mention deposit and withdraw money.

I’m also going to be setting you the challenge of using object-oriented programming to create classes and objects that represent bank accounts. 

It’s a big leap from individual functions to designing a system using objects, encapsulating data, and operations. You're not just coding now; you're engineering a mini-system!

C++ Source Code:

#include <iostream>
#include <string>

class BankAccount
{
private:
  std::string name;
  double balance;

public:
  BankAccount(std::string accountName, double initialBalance)
      : name(accountName), balance(initialBalance) {}

  void deposit(double amount)
  {
      if (amount > 0)
      {
          balance += amount;
      }
  }

  void withdraw(double amount)
  {
      if (amount <= balance)
      {
          balance -= amount;
      }
      else
      {
          std::cout << "Insufficient funds." << std::endl;
      }
  }

  void display()
  {
      std::cout << "Account: " << name << "\nBalance: $" << balance << std::endl;
  }
};

int main()
{
  std::string name;
  double initialDeposit;

  std::cout << "Enter your name: ";
  getline(std::cin, name);
  std::cout << "Enter initial deposit: ";
  std::cin >> initialDeposit;

  BankAccount account(name, initialDeposit);

  int choice;
  double amount;

  do
  {
      std::cout << "\n1. Deposit" << std::endl;
      std::cout << "2. Withdraw" << std::endl;
      std::cout << "3. Display Account" << std::endl;
      std::cout << "4. Exit" << std::endl;
      std::cout << "Enter choice: ";
      std::cin >> choice;

      switch (choice)
      {
      case 1:
          std::cout << "Enter deposit amount: ";
          std::cin >> amount;
          account.deposit(amount);
          break;
      case 2:
          std::cout << "Enter withdrawal amount: ";
          std::cin >> amount;
          account.withdraw(amount);
          break;
      case 3:
          account.display();
          break;
      case 4:
          break;
      default:
          std::cout << "Invalid choice." << std::endl;
      }
  } while (choice != 4);

  return 0;
}

Code Explanation:

This was our first foray into OOP, so let’s break down what we’ve done in this C++ project to create our banking system:

  1. We defined a BankAccount class with private member variables for account name and balance.
  2. We provided public methods (deposit, withdraw, display) for account operations.
  3. The main function allows the user to create a bank account with an initial deposit, before letting them deposit, withdraw, or display account information via a do-while loop.
  4. The switch statement in the main function handles user choices for banking operations.

If you’re still new to object-oriented programming, don’t worry! This C++ project is designed to give you the basic skills while also challenging you to layer in your other basic C++ knowledge.

By building this simple bank system, you’ll get some practical experience with the basics of class design, encapsulation, and simple banking logic in C++.

That said, how else might you extend this C++ project? Perhaps you can look into file persistence to store account data in a user file? 

What about integration with credit cards? Major providers like Visa and Mastercard will have APIs for real-world banking and e-commerce systems, so why not check these out?  

How about a message to inform the user about successful registration during the user registration process? 

And, of course, maybe you can add a login system where a user enters account credentials for validation before accessing their account details.

7. Tic-Tac-Toe Game

Now, it's time for some fun – but with a twist! Here, we’re going to build a Tic-Tac-Toe game as a way to learn array utilization and game logic. 

This C++ project also builds upon previous concepts by adding array manipulation into the mix, which is ideal for learning how to manage and use data structures.

Again, these are core skills for any C++ developer, so now’s a great time to level up and figure it out!

C++ Source Code:

#include <iostream>
#include <vector>

void drawBoard(const std::vector<std::vector<char>> &board)
{
  for (const auto &row : board)
  {
      for (char cell : row)
      {
          std::cout << cell << " ";
      }
      std::cout << std::endl;
  }
}

bool checkWin(const std::vector<std::vector<char>> &board, char player)
{
  // Check rows, columns, and diagonals for a win
  for (int i = 0; i < 3; ++i)
  {
      if ((board[i][0] == player && board[i][1] == player && board[i][2] == player) ||
          (board[0][i] == player && board[1][i] == player && board[2][i] == player))
      {
          return true;
      }
  }

  if ((board[0][0] == player && board[1][1] == player && board[2][2] == player) ||
      (board[0][2] == player && board[1][1] == player && board[2][0] == player))
  {
      return true;
  }

  return false;
}

bool checkDraw(const std::vector<std::vector<char>> &board)
{
  for (const auto &row : board)
  {
      for (char cell : row)
      {
          if (cell == ' ')
          {
              return false;
          }
      }
  }
  return true;
}

int main()
{
  std::vector<std::vector<char>> board(3, std::vector<char>(3, ' '));
  char currentPlayer = 'X';
  int row, col;
  bool gameOver = false;

  while (!gameOver)
  {
      drawBoard(board);
      std::cout << "Player " << currentPlayer << ", enter row and column (0-2): ";
      std::cin >> row >> col;

      if (board[row][col] == ' ')
      {
          board[row][col] = currentPlayer;
          gameOver = checkWin(board, currentPlayer);

          if (gameOver)
          {
              drawBoard(board);
              std::cout << "Player " << currentPlayer << " wins!" << std::endl;
          }
          else if (checkDraw(board))
          {
              drawBoard(board);
              std::cout << "It's a draw!" << std::endl;
              gameOver = true;
          }

          currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';
      }
      else
      {
          std::cout << "That spot is already taken. Try again." << std::endl;
      }
  }

  return 0;
}

Code Explanation:

I don’t think any of us need an explainer on how to play tic-tac-toe, but let’s break down what our C++ program is doing to let us play this classic game:

  1. We represent the game board with a 3x3 matrix. This is built with a vector of vectors of characters.
  2. The drawBoard function displays the current state of the board.
  3. The checkWin function checks if a player has won by completing a row, column, or diagonal.
  4. The checkDraw function checks for a draw if there are no empty spaces left.
  5. The main function handles the game loop, player input, and alternates turns between players X and O.
  6. The game continues until a player wins or there's a draw.

When you run this C++ program, two players can play by entering the row and column numbers where they want to place their marker (X or O). 

This project is great for understanding arrays/vectors, nested loops, and basic game logic in C++.

How might you alter this program to make it more user-friendly? 

For example, right now, the program uses zero-based indexing for row and column positions, but if the players don’t understand this, it might be confusing.

So, here’s a challenge for you! Alter this C++ project to accept values from 1-3 rather than 0-2 for rows and columns. These signals are probably more suer friendly, what do you think?

And if you’re feeling really adventurous, how about increasing the game from a 3x3 matrix to something larger?

8. Contact Book App

Now it’s time to create a Contact Book Application in C++ where you can get to grips with advanced data handling, such as storing, editing, searching, and deleting contact information

If you plan to attend any C++ interviews on your way to landing a C++ job, these are key skills that can help you demonstrate your knowledge.

C++ Source Code:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

struct Contact
{
  std::string name;
  std::string phone;
  std::string email;
};

void addContact(std::vector<Contact> &contacts)
{
  Contact newContact;
  std::cout << "Enter name: ";
  std::cin >> newContact.name;
  std::cout << "Enter phone: ";
  std::cin >> newContact.phone;
  std::cout << "Enter email: ";
  std::cin >> newContact.email;
  contacts.push_back(newContact);
  std::cout << "Contact added." << std::endl;
}

void displayContacts(const std::vector<Contact> &contacts)
{
  for (const auto &contact : contacts)
  {
      std::cout << "Name: " << contact.name << ", Phone: "
                << contact.phone << ", Email: " << contact.email << std::endl;
  }
}

void searchContact(const std::vector<Contact> &contacts)
{
  std::string searchTerm;
  std::cout << "Enter name to search: ";
  std::cin >> searchTerm;

  bool found = false;
  for (const auto &contact : contacts)
  {
      if (contact.name == searchTerm)
      {
          std::cout << "Name: " << contact.name << ", Phone: "
                    << contact.phone << ", Email: " << contact.email << std::endl;
          found = true;
          break;
      }
  }

  if (!found)
  {
      std::cout << "Contact not found." << std::endl;
  }
}

void deleteContact(std::vector<Contact> &contacts)
{
  std::string nameToDelete;
  std::cout << "Enter name of contact to delete: ";
  std::cin >> nameToDelete;

  auto it = std::remove_if(contacts.begin(), contacts.end(), [&](const Contact &contact)
                            { return contact.name == nameToDelete; });

  if (it != contacts.end())
  {
      contacts.erase(it, contacts.end());
      std::cout << "Contact deleted." << std::endl;
  }
  else
  {
      std::cout << "Contact not found." << std::endl;
  }
}

int main()
{
  std::vector<Contact> contacts;
  int choice;

  do
  {
      std::cout << "\n1. Add Contact" << std::endl;
      std::cout << "2. Display Contacts" << std::endl;
      std::cout << "3. Search Contact" << std::endl;
      std::cout << "4. Delete Contact" << std::endl;
      std::cout << "5. Exit" << std::endl;
      std::cout << "Enter choice: ";
      std::cin >> choice;

      switch (choice)
      {
      case 1:
          addContact(contacts);
          break;
      case 2:
          displayContacts(contacts);
          break;
      case 3:
          searchContact(contacts);
          break;
      case 4:
          deleteContact(contacts);
          break;
      case 5:
          break;
      default:
          std::cout << "Invalid choice." << std::endl;
      }
  } while (choice != 5);

  return 0;
}

Code Explanation:

How did you find that C++ project? Let’s break down the main parts of this program of this address book app:

  1. We defined a Contact struct to store the name, phone, and email of each contact.
  2. The addContact function allows users to add a new contact to the contact book.
  3. The displayContacts function lists all contacts in the contact book.
  4. The searchContact function looks for a contact by name and displays it if found.
  5. The deleteContact removes a contact from the list based on the name.
  6. The main function provides a simple menu for the user to choose between adding a new contact, displaying contacts, searching for a contact, deleting a contact, or exiting the program.
  7. We use a vector of Contact structs to store the list of contacts.

When you run this program, the user has the option to add new contacts, view the current contacts in their contact book, search for contacts, or delete contacts. 

While this program seems simple, it’s a great way to bundle the skills you’ve used in the previous 7 C++ projects while getting to grips with structured data in C++.

Now, my challenge to you is to extend this project further in any way you like! Take a look at any modern contacts app and see where this can be improved.

9. File Encryption App

Let’s now mix things up with a simple but effective File Encryption and Decryption Tool. 

If you’re interested in the field of data security systems, this project is a great primer in C++, as it’s fascinating to see how you can protect file systems with basic encryption techniques.

As a beginner’s project, we’ll stick to a simple Caesar cipher using a character shift. I like this approach, as it’s easy to understand and implement for newcomers to C++.

We’re also extending our skills in file I/O, making it a nice step up from our previous To-Do List app.

Just think, if you’ve made it this far, you're not just coding – you're safeguarding data and delving into the principles that underpin secure communication in our digital world.

C++ Source Code:

#include <iostream>
#include <fstream>
#include <string>

void encryptFile(const std::string &inputFilePath, const std::string &outputFilePath, int key)
{
  std::ifstream inputFile(inputFilePath, std::ios::binary);
  std::ofstream outputFile(outputFilePath, std::ios::binary);

  char ch;
  while (inputFile.get(ch))
  {
      outputFile.put(ch + key);
  }

  inputFile.close();
  outputFile.close();
}

void decryptFile(const std::string &inputFilePath, const std::string &outputFilePath, int key)
{
  std::ifstream inputFile(inputFilePath, std::ios::binary);
  std::ofstream outputFile(outputFilePath, std::ios::binary);

  char ch;
  while (inputFile.get(ch))
  {
      outputFile.put(ch - key);
  }

  inputFile.close();
  outputFile.close();
}

int main()
{
  std::string inputFilePath, outputFilePath;
  int choice, key;

  std::cout << "1. Encrypt File\n";
  std::cout << "2. Decrypt File\n";
  std::cout << "Enter your choice: ";
  std::cin >> choice;

  std::cout << "Enter key (integer): ";
  std::cin >> key;

  std::cout << "Enter input file path: ";
  std::cin >> inputFilePath;
  std::cout << "Enter output file path: ";
  std::cin >> outputFilePath;

  if (choice == 1)
  {
      encryptFile(inputFilePath, outputFilePath, key);
  }
  else if (choice == 2)
  {
      decryptFile(inputFilePath, outputFilePath, key);
  }
  else
  {
      std::cout << "Invalid choice." << std::endl;
  }

  return 0;
}

Code Explanation:

I really love this C++ project because it’s a great way to get some simple exposure to the powerful and potentially very complicated subject of encryption.

That said, let’s break down the main parts of our C++ program:

  1. The program uses file streams to read from an input file and write to an output file, similar to our previous projects.
  2. The encryptFile and decryptFile functions perform simple encryption and decryption by shifting characters by a given key. The key is an integer value determining how many places each character is shifted.
  3. In the encryption function, each character from the input file is shifted forward by the key value, while in the decryption function, the characters are shifted backward.
  4. The main function asks the user to choose between encrypting and decrypting a file. They’re then prompted to specify the key for the cipher and to provide the file paths.

When you run this program, you’re greeted with a really simple user interface that asks you to choose between encryption or decryption.

It’s then a matter of choosing the encryption key value and providing file names for the input and output.

Here’s a question: have you tried using the wrong encryption key? What happens?

Also, here’s a challenge for you! How might you add more complexity to your encryption technique? If you’re not sure where to start, I’ll provide some ideas.

Why not try a substitution cipher? Or perhaps a randomly generated key? Perhaps you can look at some form of login with a username and a password?

There are lots of things you can do here, so have some fun exploring the world of encryption! 

10. Chat Application

We’ve now reached the pinnacle of our C++ project series with a Chat Application. At a time when everyone's talking about AI-powered chatbots, this seems like a great starting point.

This is a super challenging and rewarding project that combines everything you’ve learned so far while introducing the fundamentals of networking, multi-threading, and advanced OOP.

That said, to keep this C++ project firmly in the beginner to improver category, I’ll keep the example fairly simple by using a basic server-client model with simplified networking.

This also means that you’ll be creating two separate programs: one for the server and one for the client.

You can then run both programs on the same machine (localhost) to test it. 

Ultimately, this C++ project ties in elements from all of our previous projects while introducing you to a client-server architecture.

Note that you’ll need to make sure your development environment supports networking libraries like Winsock (for Windows) or sockets (for Unix/Linux).

C++ Source Code - Server:

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>

int main()
{
  int server_fd, new_socket;
  struct sockaddr_in address;
  int opt = 1;
  int addrlen = sizeof(address);
  char buffer[1024] = {0};

  // Creating socket file descriptor
  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
  {
      perror("socket failed");
      exit(EXIT_FAILURE);
  }

  // Forcefully attaching socket to the port 8080
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
  {
      perror("setsockopt");
      exit(EXIT_FAILURE);
  }
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(8080);

  // Forcefully attaching socket to the port 8080
  if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
  {
      perror("bind failed");
      exit(EXIT_FAILURE);
  }
  if (listen(server_fd, 3) < 0)
  {
      perror("listen");
      exit(EXIT_FAILURE);
  }
  if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0)
  {
      perror("accept");
      exit(EXIT_FAILURE);
  }

  while (true)
  {
      memset(buffer, 0, sizeof(buffer)); // Clear the buffer
      int bytes_read = read(new_socket, buffer, sizeof(buffer));
      if (bytes_read == 0)
      {
          std::cout << "Client disconnected" << std::endl;
          break;
      }

      std::cout << "Client: " << buffer << std::endl;

      // Echo the message back to the client
      send(new_socket, buffer, strlen(buffer), 0);

      // Check if the message is a command to close the connection
      if (strcmp(buffer, "exit") == 0)
      {
          std::cout << "Exit command received. Closing connection." << std::endl;
          break;
      }
  }

  close(new_socket);
  close(server_fd);
  return 0;
}

C++ Source Code - Client:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

int main()
{
  int sock = 0, valread;
  struct sockaddr_in serv_addr;
  char buffer[1024] = {0};

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
      std::cout << "\n Socket creation error \n";
      return -1;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(8080);

  // Convert IPv4 and IPv6 addresses from text to binary form
  if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
  {
      std::cout << "\nInvalid address/ Address not supported \n";
      return -1;
  }

  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
  {
      std::cout << "\nConnection Failed \n";
      return -1;
  }

  std::string message;
  while (true)
  {
      std::cout << "Enter message (type 'exit' to close): ";
      std::getline(std::cin, message);

      if (message == "exit")
      {
          break;
      }

      send(sock, message.c_str(), message.length(), 0);

      valread = read(sock, buffer, 1024);
      std::cout << "Server: " << buffer << std::endl;
      memset(buffer, 0, sizeof(buffer)); // Clear the buffer
  }

  close(sock);
  return 0;
}

Okay, now, there’s a lot going on here, so let’s tackle this in two parts, starting with the server code, and then we’ll tackle the client code.

Server Code Explanation:

  1. The server starts by creating a socket, where AF_INET specifies the IPv4 address family and SOCK_STREAM indicates a TCP socket.
  2. We use setsockopt to set options for the socket. In our program, SO_REUSEADDR and SO_REUSEPORT allow the server to bind to a port that remains in a TIME_WAIT state.
  3. The sockaddr_in structure specifies the address and port for the socket, INADDR_ANY is used to bind the socket to all available interfaces, and htons(8080) specifies port 8080.
  4. Bind, Listen, and Accept:
    1. bind associates the socket with its local address.
    2. listen sets the socket to listen for incoming connections.
    3. accept waits for an incoming client connection. It blocks the execution until a client connects. Once a client connects, it returns a new socket specifically for the client.
  5. The server enters a loop where it listens for messages from the client using read. It then echoes back the received message using send.
  6. If "exit" is received or the client disconnects, the server breaks out of the loop, closing the client socket and its own socket before terminating.

Client Code Explanation:

  1. Similar to the server, the client creates a socket using socket(AF_INET, SOCK_STREAM, 0).
  2. The client sets up a sockaddr_in structure specifying the server's address and port to connect to. We use inet_pton to convert the IP address from text to binary form.
  3. The client establishes a connection to the server socket.
  4. The client enters a loop, prompting the user to input messages. The messages are sent to the server using send.
  5. After sending a message, the client receives the server's response (echoed message) and prints it.
  6. If the user inputs "exit", the client breaks out of the loop, closing the connection.

Overall Workflow:

Let’s now summarize the general workflow for our client-server chat app.

  • The server needs to be started first. It sets up a socket and waits for a client to connect.
  • The client, once started, establishes a connection to the server.
  • The client sends messages to the server, which the server then echoes back, demonstrating a basic two-way communication.
  • When the client sends "exit", both the client and server close their connections.

So, when you run the server and client programs, they will connect to each other (assuming both are run on the same machine using localhost).

You should then be able to see messages exchanged between the two. For now, we’ve only designed the server program to echo the client’s messages back.

After all, this is a simple example of a chat application with a client-server architecture.

But what’s great about this C++ project is that it lays the foundation for more complex chat applications involving multiple clients.

And here it comes! My challenge for you! How can you implement better message handling in this app? Perhaps with support for multiple clients that want to communicate? 

You should also know that real-world apps would involve more robust error handling and security measures. How would you handle this?

If you want to venture into the professional world of C++ development or maybe earn a C++ certification, these are great skills to have at your disposal.

And if you’re feeling really adventurous, you can even look into creating a graphical user interface!!

The sky is the limit with this C++ application, and I hope you have fun experimenting with it!

How To Setup Your C++ Environment

Before you start coding in C++, you need to make sure you have your coding environment all set up and ready to go.

Being a compiled language means that, naturally, you need to have a C++ compiler installed on your system.

If you already have a C++ compiler installed, feel free to skip this, but if not, let’s get you all set up! 

Now, naturally, the process is going to differ for each OS, so I’ve added simple steps for Windows, Mac, and Linux.

Install C++ Compiler on Windows

Download MinGW from here

Run the installer and follow the instructions, choosing your architecture (32 or 64 bit) and version.

During installation, add the MinGW/bin directory to your system's PATH environment variable.

Don’t be intimidated by this if you’re not used to working with the PATH, but it’s actually a commonly overlooked step that can trip you up later.

All you need to do is note down the MinGW installation folder’s location. This will be something like C:\Program Files\MinGW\bin

Then, open System Properties by right-clicking on My Computer and selecting Properties.

You’ll then need to click on Advanced system settings to access the System Properties window.

Head on over to the Advanced tab and click on Environment Variables.

Look under System variables and scroll until you find the PATH variable. You can then click Edit.

You should then see a list of different paths. If you can’t see MinGW, add it by clicking on New and then adding the path to your MinGW directory you noted earlier.

Make sure there are no extra spaces or characters, then click OK to close the edit window, OK on the Environment Variables window, then OK on the System Properties window

That’s it! Not that scary after all! 

Remember that after updating the PATH, you might need to restart your command prompts or applications for the changes to take effect.

The final step is to verify your Installation by opening the terminal/command prompt and running g++ --version 

If MinGW is correctly installed, it should display the version of GCC.

Install C++ Compiler on macOS

Open the terminal

Install Xcode Command Line Tools by running the command xcode-select --install 

Look for a software update popup, then click Install to download and install Xcode Command Line Tools.

Verify installation by running g++ --version

If all is well, this should show the version of Clang, which is an alias for g++ on macOs.

Install C++ Compiler on Linux (Debian & Ubuntu)

Open up your terminal, and update your package list with sudo apt update.

Install the build-essential package (which includes GCC and G++) with sudo apt install build-essential

Verify installation at the terminal by running g++ --version

If you see a GCC version, you’re all set!

Setting Up C++ In VSCode

For beginners, I’d recommend using Visual Studio Code for creating your C++ project, as it’s really easy to install a VSCode extension to work with your C++ compiler.

Of course, make sure you’ve installed VSCode on your system, but assuming you’ve already done this, just head to the extensions tab.

You can then search for C++, which should return a result for C/C++ extension by Microsoft.

Install this, and you should be good to go!

What Are Some Well-Known C++ Projects?

Some of the world's most widely used software, games, operating systems, backend infrastructure, and more rely on C++:

  • Operating Systems (OS): Microsoft Windows, macOS
  • Software Applications: Adobe Photoshop, Illustrator, and others
  • Games: World of Warcraft, Counter-Strike, Unreal Engine, Playstation, Xbox, etc
  • Graphics: Digital image processing, computer-generated graphics, etc
  • Embedded Systems: Internet of Things (IoT), flight software, etc
  • Databases: MySQL, MongoDB
  • Web browsers: Google Chrome, Mozilla Firefox, Safari, Opera
  • Backend via CGI (Common Gateway Interface): Spotify, YouTube, Amazon
  • Machine Learning: TensorFlow, Google Search
  • Business Applications: Tools for finance, civil engineering, hospitality, etc

Wrapping Up

So there you have it, the 10 best C++ projects in 2024, including a range of C++ projects for beginners to test themselves and make the leap from novice to pro. 

To help you build your skills, each of the C++ projects I’ve covered was designed to be more challenging as you make your way through the list.

This means you can approach these projects like a free C++ course. 

My goal is to help you level up your C++ skills naturally while also enhancing your portfolio with these C++ projects.

So whether you’re starting out in systems development or keen to pursue game development with C++, each of the C++ projects I’ve included is ideal for helping you achieve your goals!

Whichever C++ project you choose to build, I hope you have fun, and I wish you the best of luck with your C++ programming career!

Happy coding!

Want to take the leap from C++ developer to game developer? Check out:

Udemy's Unreal Engine 5: Learn C++ & Make Video Games

Frequently Asked Questions

1. How Will Building C++ Projects Help Me?

Building C++ projects will enhance your problem-solving skills, deepen your understanding of system-level programming, and improve your proficiency in a language that's fundamental to computer science and software development.

2. Should I Learn C++ In 2024? 

Yes, you should learn C++ in 2024 if you're interested in system/software development, game development, or fields requiring high-performance computing, as it remains a powerful and widely used language.

People are also reading:

References

1. Stack Overflow. Stack Overflow Developer Survey 2023: Most Popular Technologies [Internet]. Stack Overflow; [date unknown; cited 2024 Jan 15]. Available from: https://survey.stackoverflow.co/2023/#technology-most-popular-technologies

2. Bureau of Labor Statistics, U.S. Department of Labor. Occupational Employment and Wages, May 2022, 15-1251 Computer Programmers [Internet]. [updated 2021 Mar 31; cited 2024 Jan 15]. Available from: https://www.bls.gov/oes/current/oes151251.htm

3. MinGW-w64. Downloads [Internet]. MinGW-w64; [date unknown; cited 2024 Jan 15]. Available from: https://www.mingw-w64.org/downloads/

4. Visual Studio Code. Download Visual Studio Code [Internet]. Visual Studio Code; [date unknown; cited 2024 Jan 15]. Available from: https://code.visualstudio.com/download

By Robert Johns

Technical Editor for Hackr.io | 15+ Years in Python, Java, SQL, C++, C#, JavaScript, Ruby, PHP, .NET, MATLAB, HTML & CSS, and more... 10+ Years in Networking, Cloud, APIs, Linux | 5+ Years in Data Science | 2x PhDs in Structural & Blast Engineering

View all post by the author

Subscribe to our Newsletter for Articles, News, & Jobs.

I accept the Terms and Conditions.

Disclosure: Hackr.io is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission.

In this article

Learn More

Please login to leave comments

Sophie Käpyaho

How can I implement better message handling in the Chat Application? Well, here's a list... remove `valread` from the client. (Warn: unused-but-set-variable); fix the out-of-bounds read (`strlen(buffer)`) (CWE-170 --> CWE-126); move to an async epoll system (which I did before reviewing the article's code); handle possible `socket()` errors; handle possible `read()` errors; and clean up the code

7 months ago