A Crash Course in C++: Introducing the Language

A smooth C never made a skilled sailor

James Collerton
7 min readJun 1, 2024
Let’s get going!

Audience

In this article we will introduce the programming language C++. You will need a solid understanding of at least one other language. It will help if it’s compiled and object-oriented, but it’s not completely necessary as long as you understand the concepts.

This piece will set the scene for C++, and culminate in us printing “Hello, World” to the console. Although this may not seem very exciting, it will allow us to write more engaging code later on.

The article also holds some of my own opinions on C++ as a language. They will be coloured by my previous experiences, and are not authoritative in any sense. They are only included to give you an anecdotal taste of the language.

Here we go!

Argument

Other C languages

If you’ve heard of C++, you’ve most likely heard of at least one of the other Cs: C# (pronounced C-sharp), Objective-C and just ‘C’.

It feels odd to dive into one without understanding its place in the line up, so here’s a whistle-stop tour.

C is the mother language of all the others, and very low level. It’s often used for operating systems and firmware. You have to do things like manually allocate memory correctly. This gives you a lot of control (great!), but also a lot of room to introduce problems if you don’t know what you’re doing (not so great).

Generally, C is thought of as an imperative language. You give it a list of instructions and it goes away and does them. For a lot of applications this is perfect. However, object-orientation also brings a lot of benefits. C++, C# and Objective-C introduce this concept.

C++ adds the object-orientation layer, whilst keeping the language quite low-level. In later iterations you don’t need to worry about memory allocation too much, but you’re still in that general area. Don’t worry if that seems a bit hand-wavy, it’s best understood through looking at the code.

In my opinion, C# is very similar to Java. It’s quite high level, and you become more concerned with the code than what’s going on underneath. It’s used a lot in Microsoft projects (e.g. with the .NET framework).

Objective-C is/ was used a lot in Apple products, and is the only one I’ve no experience of. It offers similar capabilities to C++, but is updated less frequently and, for a lot of applications, is being phased out in favour of Swift.

It’s important to differentiate between languages with C in the name, and C-family programming languages. The latter group is much broader!

Why use C++

So what’s the purpose of C++? It’s used when performance is a priority, such as in video games, or IoT devices. It has most of the speed of C, but with a number of nice features sprinkled on top.

An interesting question is: ‘If C++ is as good as C, and an (allegedly) more rich language, why use C at all?’.

Well, C is good if:

  • You have constraints such as no C++ development support (C compilers are more common), or your project needs to use code already written in C.
  • The size of your program is also of utmost importance (e.g. for embedded systems).
  • You need a small language you understand completely. Although C doesn’t have a lot of the bells and whistles of C++, this can be a blessing. It means you can more completely understand all of its functionality, and not be confused by esoteric features.

Compiling

C++ is a compiled language, which means we need to translate our source code into something machine-readable before we can run it. This process is carried out by a compiler.

The alternative is interpreted languages (like Python), where the source code itself is executed step-by-step.

The advantage of using a compiled language is that the code execution is often faster and more efficient, especially as it optimises specifically for our target architecture. Additionally the resultant programs tend to be smaller than their interpreted counterparts.

When we think about the applications of C++ (video games, embedded devices etc.), this makes a lot of sense.

High level, a compiler takes in our source files and carries out three steps:

  1. Preprocessing: Gathers together all of your source code for your compiler to look at. For example, if you reference one file from another it will substitute that information into the appropriate place.
  2. Compile and assemble: The compile stage parses the output of preprocessing and generates object files. They are then converted into assembly by the assembler.
  3. Link: This brings everything from the previous step together and outputs an executable or library.

If you’ve ever come across C++, you’ll also know there’s a lot of different compilers on offer (Gnu Compiler Collection/ GCC, Clang, IBM etc.). This isn’t C++ specific (languages like Java also have this), and there’s a few good reasons for this being the case.

Mainly, different compilers are standard for different platforms. For example, GCC, which contains g++ , is generally employed on UNIX-based machines.

However, another good thing about the array of options is competition. They force each other to stay up to date, and can help developers avoid vendor lock in.

IDEs

The wide range of compilers brings us on to something else there’s a wide range of: IDEs. There’s quite a few, CLion from IntelliJ, XCode, Visual Studio etc. That’s without including the good ol’ text editor/ CLI route with Vim, Emacs etc.

As we’ll be trying to get to grips with the language from the ground up, we’ll be using VS Code and the command line. However, it’s good to know the other options.

Build Systems

Once you’ve chosen your compiler and IDE, it’s time to choose a method of building your project.

The most basic one is GNU make. Here you write a language-agnostic Makefile which, amongst other things, controls installing packages and building your program. A good example of how to use it is here.

Basic is not always good — sometimes we require more complex functionality. Bazel (and its wrapper Bazelisk) is a build tool from Google. The main advantages include it’s multiplatform, and has sandboxing and caching (including remotely), which improves build times.

The other option is Ninja: This is used for fast incremental builds. The idea is to use it with a pre-build system (a concept we’ll explore shortly), which makes all of the ‘choices’ up front, speeding up incremental builds each time you change a file.

CMake is probably the most common pre-build system. These are designed to generate configuration files for other build tools. For example, with Make we need a Makefile . CMake will generate this for us.

We can see how it’s vital for Ninja. By using it to pre-generate all of the build configuration, at build time Ninja knows exactly what it needs to do, there’s no ‘choices’ to be made and the incremental build is quicker!

Recap

OK, let’s take a step back and think about what we’ve covered:

  1. Where C++ sits in the wider programming landscape.
  2. Why we’d use C++.
  3. All the different tools we need to build a C++ program.

Already we’ve discussed a lot. The C++ ecosystem is complex and varied, with lots of decisions to be made about what we want to use. Some of the ideas may seem quite abstract, so let’s put them into practice to get a more concrete understanding.

“Hello, World!”

In our example we are going to use Bazel as our build tool, g++ from GCC as our compiler, and VS Code as our text editor.

The reason I’m not using CLion is due to the fact that there’s no community edition. VS Code, on the other hand, is free. I’ve also installed the C/ C++ extension pack to help us out.

The code, with explanation, is below.

So far so good, now let’s compile and run it.

Easy! However, our build process won’t scale as we introduce more files.

Let’s introduce Bazel. First we need to install it using the instructions here.

I’m using Bazelisk, which handles versioning for me. It’s useful as I can do things like include the executable in the repository so those using my code/ build agents don’t need to download it themselves.

The next thing we need to do is add WORKSPACE and BUILD files. The empty WORKSPACE file designates the directory as a Bazel workspace, whereas we will use the BUILD file to tell Bazel what to build.

We’ve also moved our hello-world.cpp file into a folder main and put the BUILD file inside. This is to create a package (a collection of related files and steps for how to build something out of them).

The BUILD file looks like this.

This looks very similar to our g++ command! We run it with:

bazel build //main:hello-world

Which generates the below folder structure. These are actually all convenience symlinks for the /home/user/.cache/bazel/ folder, which stores the information.

# Binaries generated here
bazel-bin

# Working directory for all actions. These are commands that
# run during the build, e.g. calling the compiler
bazel-hello-world

# All the output from the build
bazel-out

# Where the internal test runner puts test log files
bazel-testlogs

We can then run our program with:

bazel-bin/main/hello-world

For maximum points we’re also going to use CMake to generate a makefile for the project too.

The first thing we need to do is create a CMakeLists.txt file in the base directory.

Our CMake configuration file

We then run cmake . in our base directory, and it creates a Makefile in the same place.

I’m going to skip the contents for brevity, but the below help command contents gives you a clue to the kind of thing it contains.

Remember, CMake generates build configurations, it doesn’t actually run a build. We can now build and run our program using the Makefile with:

make hello-world
./hello-world

# Prints Hello, World!

Conclusion

We’ve covered quite a lot here, including:

  • C++ in the context of the other ‘C’ languages.
  • Why we use C++.
  • Compiling, including preprocessing, compilation, assembly, and linking.
  • Common IDEs, build and pre-build systems.
  • Writing our very first C++ program!

If you want to dig through the source code, the repo is here.

--

--

James Collerton

Senior Software Engineer at Spotify, Ex-Principal Engineer at the BBC