Introduction

C++ is one of the most widely used programming languages, known for its power, performance, and versatility. Whether you’re delving into system programming, game development, or high-performance applications, C++ provides the tools needed to build efficient and robust software. This post introduces the foundational building blocks of C++ and offers resources for further learning.

As of January 2025, the most widely adopted version of C++ is C++17, with C++20 rapidly gaining traction among developers. C++17 introduced several enhancements, including parallel algorithms, which have been well-received within the programming community. The subsequent release, C++20, brought significant features such as concepts, ranges, and coroutines, further modernizing the language and attracting developers to upgrade. While C++23 was officially released in 2023, its adoption is still in the early stages, as developers and organizations evaluate its new features and await comprehensive support from compilers and development tools.

1. Basics: The Building Blocks

a. Hello, World!

The classic entry point to programming is a simple program that prints “Hello, World!” to the console:

#include <iostream>  // Include the input-output stream library

int main() {
    std::cout << "Hello, World!" << std::endl;  // Print message to console
    return 0;  // Indicate successful execution
}

Key takeaways:

  • #include <iostream>: Includes the library for input and output operations.
    • Note: standard libraries are included with angled braces <> instead of double quotes ". The difference is the location where the compiler searches for the respective files. If you want to include local files, you would use double quotes: #include "myfile"
  • std::cout: Used to print to the console.
  • std::endl: Ends the line and flushes the output buffer.
  • int main(): Entry point of a C++ program.
b. Variables and Data Types

C++ supports a variety of data types and standard operators, including:

  • Primitive types: int, float, double, char, bool
  • Derived types: Arrays, Vectors, Pointers, References
  • User-defined types: Classes, Structures, Enumerations
  • Arithmetic Operators: +-*/(), %, ++, --
  • Comparison Operators: ==, !=, <, <=, >, <=

Example:

// Standard expression syntax
int age = 25;
float temperature = 36.6;
char grade = 'A';
bool isPassed = true;

// Modern initializer-list syntax (since C++ 11)
int tomatoes{80};
float tomatoePrice{0.47};
char tomatoeGrade{"B"};
bool forSale{false};

// Enum/ scoped enumerator syntax
enum class DeckMaterial {
  maple,
  bamboo,
  plastic
};

// Scoping operator :: to use an enum
double deck_price(double base_price, DeckMaterial material) {
    if(material == DeckMaterial::plastic) {
        return base_price * 0.9;
    }
    return base_price * 1.3;
}

// References, must be initialized with a variable, can't be reassigned
int balance{1000};
int& budget{balance};
int pro_computer_wheels{699};
budget -= pro_computer_wheels; // Both balance and budgets are 301

/*
   Pointers:
   Object addresses, dynamic memory allocation, can be reassigned
   Address-of operator (&) - address assignment
   Indirection operator (*) - dereferencing
   The -> operator is used to access members of an object through a pointer
*/
std::string opponent{"Solomon Lane"};
std::string* ethan{&opponent};
std::string passportName{*ethan};
int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid

// Constants
const int number_of_dragon_balls{7};
number_of_dragon_balls--; // compilation error
Pointers vs. References

Pointers and references enable indirect object access, but their capabilities and safety considerations differ. Pointers offer the flexibility of changing their target object and can be assigned null. However, this flexibility introduces risks like dereferencing null pointers or creating dangling pointers. On the other hand, references cannot be null and are bound to valid objects upon creation, avoiding these risks. Given their safer nature, references should be preferred over pointers unless the additional functionalities provided by pointers are necessary.

Arrays and Vectors

C++ offers different containers to store elements of the same type in an ordered way, std::array for containers of a fixed size and std::vector, which comes with dynamic resizing capabilities. Vectors and arrays share the same functions to access their elements, front and back and at and the [] operator. You can check the containers for emptiness with the member function empty. If you want to know the number of elements, you can use size.

#include <array>
#include <vector>

std::array<std::string, 2> indie_rock {"hello", "world"}; // Array
std::vector<int> countdown {3, 2, 1, 7, 9}; // Vector

std::vector<std::string> witches {"Holly", "Alyssa", "Shannen"};
witches.pop_back(); // Shannen is no longer with the witches
witches.emplace_back("Rose"); // Rose has joined the team

#include <unordered_set>
#include <unordered_map>

std::unordered_set<int> mySet{2, 7, 1, 8, 2, 8};
const std::unordered_map<std::string, std::string> codon_to_protein = {
	{"AUG", "Methionine"},
	{"UUU", "Phenylalanine"}, {"UUC", "Phenylalanine"},
	{"UAA", "STOP"}, {"UAG", "STOP"}, {"UGA", "STOP"}
};
c. Control Structures

C++ provides the standard control flow structures:

  • Conditional Statements:
// Standard if statement
if (age > 18) {
    std::cout << "Adult";
} else if (age > 65) {
    std::cout << "Senior";
} else {
    std::cout << "Minor";
}

// Ternery operator: used when assigning a value based on a condition
bool three = 4;
int x = three ? 3 : 0;

/* 
   Since C++17 if-statements can also include a short initialization
   statement that can be used to initialize one or more variables for 
   the if statement. Note: any variables created in the initialization 
   cannot be accessed after the end of the if statement.
*/
int num{7};
if (int v{2 * num}; v > 10) {
    return v;
} else {
    return num;
}

// Switch statement/ selection statement
int price{0};
int adults{3};
int kids{2};

switch (int group_size{adults + kids}) {
    case 1:
        price = 50;
        break;  // To fall-through remove case breaks/ returns
    case 2:
    case 3:     // continued execution 
        price = 70;
        break;
    default:
        price = group_size * 30;
}
  • Loops:
// Indefinite looping
int j = 0;
while (j < 5) {
    std::cout << j << std::endl;
    j++;
}

// Definite, or counted looping
for (int i = 0; i < 5; i++) {
    std::cout << i << std::endl;
}

// Ranged-based for loop
int myNumbers[5] = {10, 20, 30, 40, 50};
for (int i : myNumbers) {
  cout << i << "\n";
}

// Stop the execution of the loop entirely
int sum{2};
while(true) {
    sum *= 2;
    if (sum > 1000)
        break;
}

// Stops the execution of the current iteration and continues with the next one
int equal_sum{0};
for (int i{1}; i < 7; ++i) {
  if (i%2 == 1) {
    continue;
  }
  equal_sum += i;
}
d. Functions

Encapsulating logic into reusable functions is a fundamental concept in C++:

#include <string>

std::string convert(int drops) {
    std::string answer;
    if (drops % 3 == 0) answer += "Pling";
    if (drops % 5 == 0) answer += "Plang";
    if (drops % 7 == 0) answer += "Plong";
    if (answer.empty()) answer = std::to_string(drops);
    return answer;
}

int main() {
    std::string result = raindrops::convert(30);
    std::cout << result << std::endl;
    return 0;
}

/*
  Function overloading:
  Multiple functions can have the same name if the parameter list is different.
*/

// Different argument types:
void play_sound(char note);         // C, D, E, ..., B
void play_sound(string solfege);    // do, re, mi, ..., ti
void play_sound(int jianpu);        // 1, 2, 3, ..., 7

// Different number of arguments:
void play_sound(string solfege, double duration);

// Different qualifiers:
void play_sound(vector<string>& solfege);
void play_sound(const vector<string>& solfege);

/*
  Default Arguments:
  If one parameter has a default declaration, then all the parameters 
  to its right need a default declaration as well.
*/

void record_new_horse_birth(string name, int weight, string color="brown-ish");
e. Namespaces

Namespaces are used for better code organization. They can be nested, which might help to structure big code bases.

namespace my_ns {
    int foo() {
        return 44;
    }
    namespace my_inner_ns {
        int baz() {
            return 90;
        }
    }
}

namespace my_other_ns {
    int foo() {
        return -2;
    }
}

int myresult{my_ns::foo() + my_other_ns::foo() * my_ns::my_inner_ns::baz()};
f. Header and Source Files

In C++, declarations are often separated from definitions. Declarations are grouped into header files, with the respective implementations placed in source files.  The file extension for header files is .h. The definitions are located in a separate .cpp file.  Everything included in the header is available in the .cpp file. E.g., #include <string> only needs to go into the header file. Classes can become very complex, and their relation to the header/source partition might be confusing. One possible layout is to keep all the implementation details in the source file and all the declarations and member variables in the header file.

// A file named quick_math.h
#pragma once
namespace quick_math {
    double super_root(double x, int n);
}

// A file named quick_math.cpp
#include "quick_math.h"
#include <cmath>
double quick_math::super_root(double x, int n) {
    while(n) { x = std::sqrt(x), --n;}
    return x;
}

2. Object-Oriented Programming (OOP)

C++ is a multi-paradigm language, but it’s best known for supporting object-oriented programming (OOP). OOP is centred around classes – user-defined types of data with their own set of related functions.

Key OOP concepts include:

a. Classes and Objects

A class is a blueprint for creating objects. Classes can have member variables and member functions. The member selection operator accesses them .. Classes offer the option to restrict access to their members. The two basic cases are private and public. All members are private by default and must be explicitly marked to be usable outside the class.

class Car {
  public:
    std::string brand;
    int speed;
    // Default constructor
    Car () { 
      brand="default";
      speed=0;
    }
    // Secondary constructor
    Car (std::string car_brand, int car_speed) { 
      brand= car_brand;
      speed = car_speed;
    }
    // public method
    void drive() { 
      std::cout << brand << " is driving at " << speed << " km/h" << std::endl;
    }
  private:
    // private member
    int initialPrice{500}; 
};

int main() {
  Car car1;
  car1.brand = "Toyota";
  car1.speed = 120;
  car1.drive();
  return 0;
}
b. Encapsulation, Abstraction, Inheritance, Polymorphism, and Dynamic Binding
  • Encapsulation is defined as wrapping up data and information under a single unit. In Object-Oriented Programming, Encapsulation binds the data and the functions that manipulate them.
  • Abstraction means displaying only essential information and hiding the details. Data abstraction refers to providing only necessary information about the data to the outside world, hiding the background details or implementation.
  • The capability of a class to derive properties and characteristics from another class is called Inheritance. Inheritance is one of the most essential features of Object-Oriented Programming.
  • Polymorphism means having many forms. In simple words, we can define polymorphism as the ability of a message to be displayed in more than one form. C++ supports operator overloading and function overloading.
  • Dynamic Binding decides which code to execute at runtime in response to the function call. C++ has virtual functions to support this. The derived class then uses the override keyword to implement the desired functionality. Because dynamic binding is flexible, it avoids the drawbacks of static binding, which connects the function call and definition at build time

These principles allow you to build modular, reusable, and maintainable code. Explore these concepts in-depth through practice.


3. Advanced Topics

Once you’ve mastered the basics, dive deeper into:

  • Pointers and Memory Management: Understand new and delete, and manage memory efficiently.
  • Templates: Write generic and reusable code.
  • STL (Standard Template Library): Explore data structures and algorithms like vector, map, and queue.
  • Concurrency: Use threads and synchronization for parallel programming.

4. Recommended Resources for Further Learning


Conclusion

C++ is a powerful language with a steep learning curve, but mastering its foundational building blocks unlocks opportunities. Start with simple programs, build your knowledge of OOP, and expand into advanced topics as you grow. Happy coding!


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *