A Primer on C++
The purpose of this document is to give you a quick primer on C++. If you're already familiar with C++, you can safely skim or skip this document.
We'll first cover CMake
which is the build tool we will be using. We won't cover deeply on how to use it (since you won't have to) except for the basic commands to get you set up. We'll also go over the general project structure. We'll then cover structs and classes in C++. If you've programmed in Java, you might recall the notion of objects. Indeed, classes are one of the distinguishing features of C++. Finally, we'll cover some basic features of the standard library that may be helpful.
CMake
For all the projects in this class, we'll be using a build system called CMake
. Essentially, CMake
helps us manage our Make
files, and our Make
files help us compile our executables.
Executables are nearly always built in a directory called build
from your project directory. Thus, from your project directory, you should run the following
cd build cmake ..
At this point, CMake
will start to generate Make
files for you. Staying in the build directory, you can now compile the project by running make all
. You can run other targets from here as well, most notable of which is make check
, which will run your tests.
Structs and Classes
We'll introduce structs
and classes
in C++ by examples. Suppose we wish to create a class that represents a "person". Each person will have public first and last names. Each person will also have an embarrassing secret that they'll keep private.
We'll start off by declaring the following in a header file person.hpp
#pragma once #include <string> class User { public: // Constructor User(std::string first_name, std::string last_name); // Data members std::string first_name; std::string last_name; // Functions std::string CalculateFullName(); private: // Private members std::string embarrassing_secret; // Private functions std::string ConcatenateStrings(std::string s1, std::string s2) }
You might notice that we've declared functions but haven't defined them. We'll define the implementations in a C++ file person.cxx
. We strongly prefer you use the this->
notation for accessing member variables and methods.
#include "person.hpp" User::User(std::string first_name, std::string last_name, std::string secret) { this->first_name = first_name; this->last_name = last_name; this->embarrassing_secret = secret; } std::string User::CalculateFullName() { return this->ConcatenateStrings(this->first_name, this->last_name); } std::string User::ConcatenateStrings(std::string s1, std::string s2) { return (s1 + s2); }
Finally, we can run in a main.cxx
file
#include "person.hpp" #include <iostream> int main() { User crypto_alice = User("Alice", "the Allstar", ""); std::cout << crypto_alice.CalculateFullName() << std::endl; }
A struct
is the same as a class in C++ except that its default visiblity is public. In this course, we'll often use struct
s to group together related data and classes to encapsulate bigger objects. We give an example of a struct
below:
// Struct declaration struct Coordinate2D { double x; double y; double AddCoordinates(); } // Defining the function double Coordinate2D::AddCoordinates() { return (x + y) }; // Some ways of initializing a struct Coordinate2D origin = {0, 0}; Coordinate2D cs1515; cs1515.x = 15; cs1515.y = 15;
The standard library
The standard library in C++ is rich in features. We'll go over and give examples of the most common features.
Input and Output Streams
In this section we'll give an example of the input and output streams std::cin
and std::cout
. These streams are used for reading input and printing output, respectively. For example, we can write the following program to continuously get input from the user and print it back to them:
#include <iostream> #include <string> int main() { while (true) { std::string input; std::cin >> input; std::cout << "You typed: " << input << "!" << std::endl; } }
You'll notice we've included <string>
. This is the header file for the standard library implementation of strings which we've implicitly been working with. We include header files when we want to import functionality from another file or library.
Vectors
Vectors in C++ are essentially dynamically sized arrays. We give the following example to illustrate important methods you may find helpful.
#include <vector> // Initialize an empty vector std::vector<int> v1; v1.push_back(1); v1.push_back(2); // Now v1 looks like {1, 2} std::cout << v1.size() << std::endl; // This will print out 2 std::vector<int> v2 = {3, 4}; // Insert all of v2 onto the end of v1 v1.insert(v1.end(), v2.begin(), v2.end()); std::cout << v1 << std::endl; // Now v1 looks like {1, 2, 3, 4}
Pairs and Tuples
Often times we'll want to return a pair of tuple of values. In C++, the std::pair
and std::tuple
can help us with this.
#include <utility> // For pairs #include <tuple> // For tuples #include <string> // For strings std::pair<int, std::string> my_pair = std::make_pair(1, "second"); std::cout << simple_pair.first << std::endl; // Prints 1 std::cout << simple_pair.second << std::endl; // Prints "second" std::tuple<int, double, std::string> my_tuple = std::make_tuple(15, 3.14, "third"); std::cout << std::get<0>(my_tuple) << std::endl; // Prints 15 std::cout << std::get<1>(my_tuple) << std::endl; // Prints 3.14 std::cout << std::get<2>(my_tuple) << std::endl; // Prints "third"
Shared and Unique Pointers
Every object in your program is stored somewhere in memory, and that memory location has an address. We call a variable that holds a memory location a pointer. In C++, there are also "smart pointers" that are wrappers around raw pointers.
With smart pointers you still have your classic operators like *
and ->
, but in addition you get the benefit of lifetime management provided by the class. There are a couple of smart pointers, but the main ones to know of are std::unique_ptr
and std::shared_ptr
. Their uses are demonstrated below:
// Assume we have a class called "SomeClass" whose constructor takes in 2 arguments. std::unique_ptr<SomeClass> ptr = std::make_unique_ptr<SomeClass>(arg1, arg2); std::shared_ptr<SomeClass> ptr = std::make_shared_ptr<SomeClass>(arg1, arg2);
A note on namespace
s
Namespaces act as a "scope" on the names of functions and classes.
To see why they are useful, consider the fact that the standard library and the Boost library both have implementations of array-like classes and both call them array
. Namespacing allows this to be possible by preventing name collisions i.e.
#include <array> #include <boost/array.hpp> std::array<int> my_std_array; boost::array<int> my_boost_array;
More about our project structure
Our projects are all structures in a very standard way:
. ├── CMakeLists.txt ├── Doxyfile.in ├── format ├── build │ └── test.sh ├── cmake │ ├── Boost.cmake │ ├── Cryptopp.cmake │ ├── Curses.cmake │ ├── Doctest.cmake │ ├── Documentation.cmake │ └── Warnings.cmake ├── include │ ├── drivers │ │ ├── cli_driver.hpp │ │ ├── crypto_driver.hpp │ │ └── network_driver.hpp │ └── pkg │ └── client.hpp ├── include-shared │ ├── colors.hpp │ ├── logger.hpp │ ├── messages.hpp │ └── util.hpp ├── src │ ├── cmd │ │ └── main.cxx │ ├── drivers │ │ ├── cli_driver.cxx │ │ ├── crypto_driver.cxx │ │ └── network_driver.cxx │ └── pkg │ └── client.cxx ├── src-shared │ ├── logger.cxx │ ├── messages.cxx │ └── util.cxx └── test ├── CMakeLists.txt ├── test.cxx
The files in the .
and cmake
directories manage the CMake
project. The ./format
script runs clang-format
on your code; you should run this in your Docker container periodically. The test
directory holds tests. The interesting folders are include
, include-shared
, src
, and src-shared
. We have a distinction between shared and non-shared libraries for the purposes of autograding. In general, the include
folders hold header files, and the src
folders hold code files. Each of the folders may be subdivides into further packages to allow ease of navigation. More on what each file does can be found in the project handouts.
More resources
There are many other interesting topics in C++ such as polymorphism, type deduduction, exception handling, etc. that we will not get into for this quick introduction. However, the following resources should be helpful if you are looking for more: