#include <iostream>
/* Hello World program written in C++. */
int main(void) {
std::cout << "Hello, World!" << std::endl; // output some text
return 0; // 0 means success
}
Download hello.cpp
Compilation can be done with either or
(part of the GNU Compiler Collection, GCC).
clang $INFILE -o $PROGRAM_NAME
$INFILE -o $PROGRAM_NAME
While <stdio.h>
(printf, scanf etc.) is available,
C++ allows using I/O streams
#include <iostream>
/* Hello World program written in C++. */
int main(void) {
std::cout << "Hello, World!" << std::endl; // output some text
return 0; // 0 means success
}
#include <iostream> // allows using std::cout, std::cin and std::endl
// main function - C++ programs start their execution here
int main(void) {
int number;
std::cout << "Please enter an integer: "; // writing to stdout
std::cin >> number; // reading user input
std::cout << "You've entered " << number << std::endl;
return 0; // indicate successful termination to environment
} // blocks are delimited with curly braces
Download input.cpp
C++ has a native bool
data type
C++ also offers constructor initialization
()
and
uniform initialization {}
#include <iostream>
int main() {
bool b = true; // c-like initialization
char c('x'); // constructor initialization (only valid during declaration)
int i {-5}; // uniform initialization (only valid during declaration)
std::cout << b << std::endl;
std::cout << c << std::endl;
std::cout << i << std::endl;
return 0;
}
Identifiers are only valid in their defining block
#include <iostream>
int main() {
{
int number = 3;
}
// std::cout << number << std::endl; // error: use of undeclared identifier
return 0;
}
Download block_scope.cpp
C++ offers type deduction: auto
and
decltype
Both should only be used to increase readability
#include <iostream>
int main() {
bool b1(true);
auto b2 = not b1; // `bool b2` deducted from assignment
char c1(65);
decltype(c1) c2; // `char c2` deducted without assignment
c2 = 66;
std::cout << b1 << " " << b2 << std::endl;
std::cout << c1 << " " << c2 << std::endl;
return 0;
}
C++ supports references which are more programmer friendly than pointers
#include <iostream>
int main(void) {
int j = 3;
int k = 100;
int* i = &j; // C-style pointer
int& m = j; // C++ reference
int& n = m; // also references j
n = 2;
m = k; // value assignment (references always "point" to the same memory)
std::cout << "i: " << (*i) << std::endl;
std::cout << "m: " << m << std::endl;
std::cout << "n: " << n << std::endl;
}
The C++ standard library offers container data types
#include <iostream>
#include <string>
#include <vector>
int main() {
char sep('\t'); // single character (escaped tab key)
std::string name("Amelie"); // C++ string
std::vector<double> numbers(3); // a managed array of doubles
std::cout << name << std::endl;
for (int i = 0; i < numbers.size(); ++i) {
std::cout << numbers[i] << sep;
}
std::cout << std::endl;
return 0;
}
if
and else
if (expression) {
// block
} else if (expression) {
// block
} else {
block
}
The ternary operator provides a shorthand
Type result = condition ? value_if_true : value_if_false;
if
and else
#include <iostream>
int main() {
int guess = 5; // assume it was entered by a user
if (guess == 4) { // guaranteed random guess, used a die
std::cout << "You won!" << std::endl;
} else {
std::cout << "Better luck next time, loser!" << std::endl;
}
return 0;
}
switch
The C++ switch statement jumps to the block of code matching the value
of an expression.
It executes one or multiple code blocks among many alternatives.
switch (expression) {
case constant1:
// statements
break; // without break, execution of the following blocks continues
case constant2:
// statements
break;
// ...
default:
// statements
}
switch
#include <iostream>
int main(int argc, char* argv[]) {
switch (argc) { // switch evaluates an expression: (argc)
case 1: // if the result of the expression resolves to 1, jump here
std::cout << "Only the command was entered." << std::endl;
break; // break - jump out of the 'switch' block to avoid falltrough
case 2:
std::cout << "Command plus one argument" << std::endl;
break;
case 3:
std::cout << "Command plus two arguments" << std::endl;
break;
default: // any other value of the expression jumps here
std::cout << "Command plus " << argc-1 << " arguments" << std::endl; break;
}
return 0;
}
while
Loopswhile (expression) {
// block
}
do ... while
: run code block at least once
regardless of the expression
do {
// block
} while (expression);
#include <iostream>
int main() {
int n = 10;
while (n > 0) { // execute block while expression evaluates to `true`
std::cout << n << ", ";
--n; // avoid side effects in statement above
}
std::cout << "FIRE!" << std::endl;
return 0;
}
#include <iostream>
int main() {
bool condition = false;
do {
std::cout << "Do this at least once." << std::endl;
} while (condition);
std::cout << "FIRE!" << std::endl;
return 0;
}
for
Loopsfor (initialization; condition; update_statement) {
// block
}
initialization
and update_statement
are optional
Every for
loop can be expressed as while
loop
// initialization
for (; condition; ) {
// block
// update_statement;
}
// initialization
while (condition) {
// block
// update_statement
}
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names = {"Pat", "Chris", "Sue", "Steve", "Anne"};
for (std::vector<std::string>::size_type i(0); i < names.size(); ++i) {
std::cout << names[i] << std::endl;
}
return 0;
}
C++ provides iterators (incl. reverse and const iterators)
for (auto it = container.begin(); it != container.end(); ++it) {
// block using `*it`
}
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names = {"Pat", "Chris", "Sue", "Steve", "Anne"};
// use reverse iterators
for (auto it = names.crbegin(); it != names.crend(); it++) {
std::cout << *it << std::endl; // dereference the iterator
}
std::cout << std::endl;
return 0;
}
C++ provides easy access each element in a container
for (const auto& element : container) {
// block
}
#include <iostream>
#include <string>
#include <vector>
using std::cout;
int main() {
std::vector<std::string> names = {"Pat", "Chris", "Sue", "Steve", "Anne"};
for (const auto& name : names) {
cout << name << " ";
}
cout << "\n";
}
aka. type signature or type annotation
Defines the data types of the parameters and return value
For example, a function that returns the sum of two integers:
(int)(int, int)
aka. function prototype or function interface
For example, a function that returns the sum of two integers:
int sum(int a, int b);
The parameter names are optional:
int sum(int, int);
Type function_name(Type parameter1, Type parameter2, ...) { body }
For example, a function that returns the sum of two integers:
int sum(int a, int b) {
return a + b;
}
By default, C++ copies argument values to function parameters
#include <iostream>
void pass_by_value(int i) {
i = 5;
std::cout << "i: " << i << " (at the end of the called function)" << std::endl;
}
int main() {
int i = 3;
std::cout << "i: " << i << std::endl;
pass_by_value(i);
std::cout << "i: " << i << " (after returning from function)" << std::endl;
return 0;
}
C++ allows passing references to arguments
#include <iostream>
void pass_by_reference(int& i) {
i = 5;
std::cout << "i: " << i << " (at the end of the called function)" << std::endl;
}
int main() {
int i = 3;
std::cout << "i: " << i << std::endl;
pass_by_reference(i);
std::cout << "i: " << i << " (after returning from function)" << std::endl;
return 0;
}
The declaration may contain default parameters.
#include <iostream>
void increment(int& i, int value = 1);
int main(void) {
int num {5};
increment(num, 5);
increment(num);
increment(num);
std::cout << "num: " << num << std::endl;
}
void increment(int& i, int value) {
i += value;
}
C++ allows function names to be used in multiple signatures
#include <iostream>
void print_array(int array[], size_t count); // function declaration
void print_array(double* array, size_t count); // overload function
int main(void) {
int a1[] {1, 2, 3, 4};
double a2[] {3.7, 9.4, 1.1, 12.9, -0.3};
print_array(a1, 4);
print_array(a2, 5);
return 0;
}
void print_array(int array[], size_t count) {
for (size_t i = 0; i < count; ++i) {
std::cout << array[i] << std::endl;
}
}
void print_array(double* array, size_t count) {
while (count) {
std::cout << *array << std::endl;
++array;
--count;
}
}
C++ functions can operate with generic types to avoid code duplication
#include <iostream>
template <class Type> // compiler will generate a function for required types
void print_array(Type* array, size_t count);
int main(void) {
int a1[] {1, 2, 3, 4};
double a2[] {3.7, 9.4, 1.1, 12.9, -0.3};
print_array(a1, 4);
print_array(a2, 5);
return 0;
}
template <class Type>
void print_array(Type* array, size_t count) {
while (count) {
std::cout << *array << std::endl;
++array;
--count;
}
}
C++ handles namespaces explicitly.
It is possible to avoid constantly prepending a namespace with the
using
keyword.
#include <iostream>
using std::cout;
using std::endl;
int main(void) {
cout << "Namespaces are a honking great thing." << endl;
return 0;
}
Use your own namespace
#include <iostream>
namespace ns {
void say_hello();
} // namespace ns
int main(void) {
ns::say_hello();
}
namespace ns {
void say_hello() {
std::cout << "Hello!" << std::endl;
}
} // namespace ns
Avoid name collisions
#include <iostream>
namespace a {
void say_hello() {
std::cout << "Hello!" << std::endl;
}
} // namespace a
namespace b {
void say_hello() {
std::cout << "Bonjour!" << std::endl;
}
} // namespace b
int main(void) {
a::say_hello();
b::say_hello();
}
C++ has too much more to offer to stuff into a single presentation. Good places to start looking for more are