Summary of the C++ language

Variable declaration

Variables can be declared anywhere in the code, not just at the start of a block. Their scope is up until the end of the enclosing block. If a variable is declared (for example) in a for statement, as in:

for (int i = 0; i < 10; i++)
{
}

then the declaration is outside the braces, so i remains defined after the end of the loop.

When a new structure (etc.) variable is declared, it no longer needs the struct (etc.) keyword before the structure name.

[struct] SName Variable;

By using the scope resolution operator, a file level variable can be referenced even if a variable of the same name has been declared locally.

VarName 
accesses the local variable
::VarName 
accesses the global variable

Operators new, delete

The new operator allocates a memory heap block large enough to hold type, and returns a pointer to it.

type* pVariable = new type;
¦
delete pVariable;

Note the slightly different syntax for arrays:

type* pVariable = new type[size];
¦
delete[] pVariable;

Overloaded functions

Multiple functions can be defined with the same name, providing they have different numbers of parameters, or at least one parameter has a different type.

module.h   module.cpp   usercode.cpp
short Func(short A);

short Func(short A, short B);

long Func(long A);
 
short Func(short A);
{ … }

short Func(short A, short B);
{ … }

long Func(long A);
{ … }
 
X = Func(Y);
The compiler calls the appropriate function based on the type of Y.

Default function parameters

Default values can be declared for function parameters, allowing them to be omitted when the function is called.

module.h

 

module.cpp

 

usercode.cpp

int Func(int A, int B = 0);
 
int Func(int A, int B);
{ … }
 
X = Func(Y);
is exactly equivalent to:
X = Func(Y, 0);

Reference variables

These are very similar to pointer variables:

Reference variable:

 

Pointer variable:

type& RefVar = Var;

RefVar = expression;
 
type* pPtrVar = &Var;

*pPtrVar = expression;

All uses of RefVar are exactly equivalent to using Var; RefVar is effectively an alias for Var. Unlike a pointer, RefVar cannot be reassigned to refer to another variable.

Reference variables are most useful as the parameters or return value of a function.

module.h

 

module.cpp

 

usercode.cpp

void Func1(int& A);

int& Func2(void);
 
void Func1(int& A)
{
A = 0;
return;
}

int& Func2(void)
{
return B;
}
 
Func1(X);
Results in X being set to zero.

Func2() = 0;
Results in B being set to zero.

Classes

A class encapsulates data variables and code functions into one object. The data and functions are called members of that class.

The format of a class is similar to a struct; a struct can be used like a class whose elements (members) are all public. A class object may be passed to or returned by a function using exactly the same syntax as for a structure.

module.h

 

module.cpp

 

usercode.cpp

Declaration

class CName
{
public|protected|private:
type m_Var;

type Func1(parameters);

type Func2(parameters)
{
In-line function code.
}
};
 

Implementation

type CName::Func1(parameters)
{
all member data and functions (whether public, protected, or private) can be directly referenced as:
m_Var
FuncN(parameters)
or, more explicitly, as:
this->m_Var
this->FuncN(parameters)
}
 

Instance

CName nameObject;

nameObject.m_Var
Accesses a public variable within the class.

nameObject.Func(parameters)
Calls a public function within the class.

Within a class function, the this keyword is a pointer to the current instance of this class. It’s effectively an additional parameter to the function.

Note the convention is to prefix the name of a class with an uppercase ‘C’, and to prefix the name of any member variables with a ‘m_’.

Constructors

If a class CName declares a function named CName, this is the class’s constructor function, which is automatically called whenever a new instance of the class is created.

The constructor function may be overloaded, to allow different constructor functions to be called according to the parameters.

The constructor function must be declared without any return type.

module.h

 

module.cpp

 

usercode.cpp

Declaration

class CName
{
public:
CName(void);
CName(params);
};
 

Implementation

CName::CName(void)
{ … }

CName::CName(params)
{ … }
 

Instance

CName nameObject;
or
CName* pNameObject = new CName;
calls constructor.

To call the alternative constructor:
CName obj(params);
CName* pObj = new CName(params);

If an array of objects is created, the constructor function is called for each object in turn:

CName nameObject[number];

Note that calling the constructor always creates a new instance of the class: the constructor can’t be called like an ordinary function. Therefore, if a class contains another class as a member variable, that class’s constructor can’t be called directly. A special syntax is provided for initialising member variables, including member classes:

module.h

 

module.cpp

Declaration

class CName
{
public:
CName(params);

CClass m_class;
int m_i1;
int m_i2;
};
 

Implementation

CName::CName(params) :
m_class(params), calls CClass’s constructor
m_i1(n) equivalent to m_i1 = n
{
m_i2 = n; equivalent to :m_i2(n)
}

Destructor

If a class CName declares a function named ~CName, this is the class’s destructor function, which is automatically called whenever the object (class instance) goes out of scope - e.g. at the end of a function where it is locally defined.

module.h

 

module.cpp

Declaration

class CName
{
public:
~CName(void);
};
 

Implementation

CName::~CName(void)
{ … }

The destructor function has no parameters, and cannot be overloaded.

Inheritance (base and derived classes)

A class can be derived from a base class. A derived class inherits all data and functions in the base class, except for the constructor and destructor functions.

module.h

 

module.cpp

Declaration

class CName : public CBase
{
public:
CName(parameters);
};
 

Implementation

CName::CName(parameters) : CBase()
{ … }

The derived class’s constructor should call the base class’s constructor, in the same way as for a member variable (via the ":CBase" statement).

The derived class may add extra data or functions of its own to those inherited from the base class. If the derived class defines a variable/function with the same name as one in the base class, the base class member can still be accessed (assuming it’s either public or protected) using "CBase::MemberName".

A class can be derived from multiple base classes, in which case it inherits all their members.

module.h

 

module.cpp

Declaration

class CName:
public CBase1,
public CBase2,
public CBase3
{
public:
CName(parameters);
};
 

Implementation

CName::CName(parameters):
CBase1(),
CBase2(),
CBase3()
{ … }

Any name conflicts between the members in the various classes must be resolved by referring to them using "CBaseN::MemberName".

Public, Protected, and Private

The accessiblity of a variable or function depends on whether it follows a public, protected, or private keyword in the class declaration:

public   Accessible by any code internal or external ("user" code) to the class.
protected   Only accessible by code internal to the class, or internal to any class derived from this class. Not accessible by any code external to the class.
private   Only accessible by code internal to the class (member functions). Not accessible by a derived class, nor by any code external to the class.

If the class being declared is derived, the keyword preceding the base class name affects the status of the members that the derived class inherits:

public   The base class’ public, protected, private members remain public, protected, private respectively.
protected   The base class’ public members become protected in the derived class. Member functions in the derived class (and classes derived from it) may access the members, but external code using an instance of the derived class may not.
private   All the base class’ members become private in the derived class. Member functions in the derived class may access the members, but classes derived from it and external code using an instance of the derived class may not.

Individual members can inherit a different status if the relevant base class members are listed following the appropriate keyword in the derived class’ declaration.

module.h

Base Declaration

class CBase
{
public:
type Func(parameters);
};

Derived Declaration

class CDerived : private CBase
{
public:
CBase::Func;
Func remains public.
};

Friends

A class can allow a specific other class or function full access to its private and protected members by declaring the class or function as a friend.

module.h

Declaration

class CName1
{
friend class CName;
friend type Func(parameters);
public:
};

Polymorphism

A pointer to a base class can be assigned to point to any class derived from that class. However, the pointer can only access members in the base class, even if the derived class has added members of the same name.

module.h

 

module.cpp

 

usercode.cpp

Base Declaration

class CBase
{
public:
type Func(parameters);
};

Derived Declaration

class CDerived: public CBase
{
public:
type Func(parameters);
};
 

Base Implementation

type CBase::Func(parameters)
{ … }

Derived Implementation

type CDerived::Func(parameters)
{ … }
 
CDerived derivedObj;
Creates an instance of the CDerived class (object).

CBase* pBaseObj = &derivedObj;
Creates a pointer to a CBase object, but the location of the CDerived object is assigned to it. Allowed because CDerived is derived from CBase.

pBaseObj->Func();
Calls CBase’s Func, not CDerived’s Func.

Virtual functions

A function (of the same name) in a base and derived class may be declared as virtual. Calls to that function via a pointer to the base class are then linked at run-time, via a look-up table, so that the function actually called is the function in the class being pointed to.

module.h

 

module.cpp

 

usercode.cpp

Base Declaration

class CBase
{
public:
virtual type Func(parameters);
};

Derived Declaration

class CDerived: public CBase
{
public:
virtual type Func(parameters);
};
 

Base Implementation

type CBase::Func(parameters)
{ … }

Derived Implementation

type CDerived::Func(parameters)
{ … }
 
CDerived derivedObj;
CBase* pBaseObj = &derivedObj;

pBaseObj->Func();
Calls CDerived’s Func.

The function must be declared identically in the base class and all derived classes that provide their own version.

Abstract classes

If the base class doesn’t provide an implementation for a virtual function, the function becomes a pure virtual function, and the class becomes an abstract class. It is not allowed nor possible to create an instance of an abstract class: it may only be used to derive classes. A derived class can be created if it provides an implementation for all pure virtual functions it inherits.

module.h

 

module.cpp

 

usercode.cpp

Base Declaration

class CBase
{
public:
virtual type Func(params) = 0;
};

Derived Declaration

class CDerived: public CBase
{
public:
virtual type Func(parameters);
};
 







Derived Implementation

type CDerived::Func(parameters)
{ … }
 
CDerived derivedObj;
CBase* pBaseObj = &derivedObj;

pBaseObj->Func();
Calls CDerived’s Func.

The declaration of the pure virtual function must be followed by "= 0".

Member functions in the base class can call the pure virtual function: the calls will be redirected to the implemented function in the relevant derived class.

static functions and variables

Variables declared in a class with the static keyword are common to all objects of that class. This applies even to variables declared as static within a member function – such a variable is effectively a static member variable, which can only be accessed from within that function.

module.h

 

module.cpp

Declaration

class CName
{
static type m_Var;
};
 

Implementation

type CName::m_Var = initial value;

Functions declared in a class with the static keyword can only access static variables (and other static functions).

const functions

A member function declared as const, as in:

type Func(parameters) const;

can not modify any member variables within that class – i.e. the class object is not affected by calling the function.

Operator Overloading

Functions can be defined which allow ‘standard’ operators to be used with user-defined data types (such as classes). Both binary and unary operators can be overloaded; some (such as "+") can have both binary and unary overload functions declared.

module.h

 

module.cpp

 

usercode.cpp

Declaration

type operatorop1(type A);


type operatorop2(type A, type B);
 

Implementation

type operatorop1(type A)
{ … }

type operatorop2(type A, type B)
{ … }
 
X = op1 Y;
is exactly equivalent to:
X = operatorop1(Y);

X = Y op2 Z;
is exactly equivalent to:
X = operatorop2(Y, Z);

The operator overload function can be declared within the class to which it applies. Remember that the this keyword is effectively the first parameter to any function within a class.

module.h

 

module.cpp

 

usercode.cpp

Declaration

class CName
{
public:
type operatorop1(void);
type operatorop2(CName B);
};
 

Implementation

type CName::operatorop1(void)
{ … }

type CName::operatorop2(CName B)
{ … }
 
X = op1 Y;
is exactly equivalent to:
X = Y.operatorop1();

X = Y op2 Z;
is exactly equivalent to:
X = Y.operatorop2(Z);

The following operators may be overloaded:

* / + - % ^ & | ~
*= /= += -= %= ^= &= |=
&& || ! , = < > <= >= == !=
++ -- << >> <<= >>= -> ->* [] () new delete

In addition, user-defined type conversions can be defined:

module.h

 

module.cpp

 

usercode.cpp

Declaration

class CName
{
public:
operator type(void);
};
 

Implementation

CName::operator type(void)
{ … }
 
CName Y;

type X = Y;
is exactly equivalent to:
type X = Y.operator type();

Casting

Dynamic casting converts a pointer (or a reference) to one class into a pointer to another (derived or base) class, checking for the validity of the cast. If a run time check fails, the resulting pointer is null, and a bad_cast exception is thrown.

module.h   usercode.cpp
class CBase
{
};

class CDerived : public CBase
{
};
 
Upcast (derived to base) - only compile time check needed:
CBase* pBase = dynamic_cast<CBase*>(pDerived);

Downcast (base to derived) - run time check that the object really is an instance of CDerived:
CDerived* pDerived = dynamic_cast<CDerived*>(pBase);

Run time check to get a pointer to the complete object:
void* pv = dynamic_cast<void*>(pBase);

Static casting converts any one type to any other type, without any run time checking. It uses any standard or user-defined type conversions (see operator overloading) which are defined.

type1 var1;
type2
var2 = static_cast<type2>(var1);

Const casting keeps the original type, but can remove any const or volatile attributes - only really useful with pointers.

const type* pVar1;
type
* pVar2 = const_cast<type*>(pVar1);

Re-interpret casting simply forces a value of one type to be treated as a value of a different type.

type1 var1;
type2
var2 = reinterpret_cast<type2>(var1);

Namespaces

By default, all global identifiers (e.g. function, variable, class names) belong to the "global" namespace. However, they can be declared as belonging to a named namespace.

namespace name
{
type variable;
}

Identifiers only need to be unique within each namespace, allowing a name in one namespace to be duplicated in another. To refer to an identifier in a specific namespace:

x = name::variable;
 or
using namespace name;
x = variable;
 or
using name::variable;
x = variable;