- C++ Syntax Cheat Sheet
Here's a simple class representing a polygon, a shape with any number of sides.
The class declaration typically goes in the .h
file. The declaration gives the class name, any classes it may extend, declares the members and methods, and declares which members/methods are public, private, or protected.
class Polygon {
// Private members and methods are only accessible via methods in the class definition
private:
int num_sides; // Number of sides
// Protected members and methods are only accessible in the class definition or by classes who extend this class
protected:
std::string name; // Name of the polygon
// Public members and methods are accessible to anyone who creates an instance of the class
public:
// Constructors
Polygon(const int num_sides, const std::string &name); // <--- This constructor takes the number of sides and name as arguments
// Getters and Setters
const int GetNumSides(void) const;
void SetNumSides(const int num_sides);
const std::string & GetName(void) const;
void SetName(const std::string &name);
}; // <--- Don't forget the semicolon!
#include "Polygon.h" // <--- Obtains the class declaration
// Constructor
// You must scope the method definitions with the class name (Polygon::)
Polygon::Polygon(const int num_sides, const std::string &name) {
this->num_sides = num_sides; // 'this' refers to the instance of the class. Members are accessed via pointers
this->name = name;
}
// Get the number of sides
const int Polygon::GetNumSides(void) const {
return this->num_sides;
}
// Set the number of sides
void Polygon::SetNumSides(const int num_sides) {
this->num_sides = num_sides;
}
// Get the polygon name
const std::string & Polygon::GetName(void) const {
return this->name;
}
// Set the polygon name
void Polygon::SetName(const std::string &name) {
this->name = name;
}
#include <string>
#include "Polygon.h" // <--- Obtains the class declaration
int main(int argc, char *argv[]) {
// Create a polygon with 4 sides and the name "Rectangle"
Polygon polygon = Polygon(4, "Rectangle");
// Check number of sides -- Prints "Rectangle has 4 sides"
std::cout << polygon.GetName() << " has " << polygon.GetNumSides() << " sides"<< std::endl;
// Change number of sides to 3 and name to "Triangle"
polygon.SetNumSides(3);
polygon.SetName("Triangle");
}
A shortcut often used for Getters/Setters is to define them in the class declaration (.h
) file as follows:
class Car {
private:
int year;
std::string make;
public:
const int GetYear(void) const { return this->year; }
void SetYear(const int year) { this->year = year; }
const std::string & GetMake(void) const { return this->make; }
void SetMake(const std::string &make) { this->make = make; }
};
Another important consideration: If you have getters and setters for all of your members, you may want to reconsider the design of your class. It is more often than not that having getters and setters for every member is indicative of poor planning of the class design and interface. Getters are very common, but setters should be used more carefully. Should you have set the variable in the constructor? Is it set somewhere else in another method, perhaps even indirectly?
A class can extend another class, meaning that the new class inherits all of the data from the other class, and can also override its methods, add new members, etc. Inheritance is the key feature required for polymorphism.
Example: the class Rectangle
can inherit the class Polygon
. You would then say that Rectangle
extends Polygon
, or that class Rectangle
is a sub-class of Polygon
. In plain English, this means that a Rectangle
is a more specialized version of a Polygon
.
#include "Polygon.h" // <--- You must include the declaration in order to extend the class
class Rectangle: public Polygon {
private: // <--- The members 'num_sides' and 'name' are already inherited from Polygon
int length;
int width;
public:
// Constructors
Rectangle(const std::string &name);
Rectangle(const std::string &name, const int length, const int width);
// Getters and Setters <--- The methods 'GetNumSides()', 'SetNumSides()', 'GetName()' and 'SetName()' are already inherited from Polygon
const int GetLength(void) const { return this->length; }
void SetLength(const int) { this->length = length; }
const int GetWidth(void) const { return this->width; }
void SetWidth(const int) { this->width = width; }
// Other Methods
const int Area(void) const;
};
#include "Rectangle.h" // <--- Only need to include 'Rectangle', since 'Polygon' is included in 'Rectangle.h'
// This constructor calls the superclass (Polygon) constructor and sets the name and number of sides to '4', and then sets the length and width
Rectangle::Rectangle(const std::string &name, const int length, const int width) : Polygon(4, name) {
this->length = length;
this->width = width;
}
// This constructor calls the superclass (Polygon) constructor, but sets the length and width to a constant value
Rectangle::Rectangle(const std::string &name) : Polygon(4, name) {
this->length = 1;
this->width = 1;
}
// Compute the area of the rectangle
const int Rectangle::Area(void) const {
return this->length * this->width;
}
#include "Rectangle.h"
int main(int argc, char *argv[]) {
Rectangle rectangle = Rectangle("Square", 6, 6);
// Prints "Square has 4 sides, and an area of 36"
std::cout << rectangle.GetName() << " has " << rectangle.GetNumSides() << " sides, and an area of " << rectangle.Area() << std::endl;
}
The keyword explicit
should be used in single-argument constructors to avoid the following situation. Consider the class Array
:
class Array {
public:
Array(int size) {
this->size = size;
}
private:
int size;
};
The following is now legal but ambiguous:
Array array = 12345;
It ends up being the equivalent of this:
Array array = Array(12345);
That's fine, one would suppose, but what about the following:
// Method PrintArray is defined as: Array::Print(const Array &array)
array.Print(12345);
Uh-oh. That's now legal, compilable code, but what does it mean? It is extremely unclear to the user.
To fix this, declare the single-argument Array
constructor as explicit
:
class Array {
public:
explicit Array(int size) {
this->size = size;
}
};
Now you can only use the print method as follows:
array.Print(Array(12345));
asm
auto
const
constexpr
(since C++11)
explicit
export
(until C++11)
extern
(language linkage)
friend
inline
mutable
noexcept
(operator)
noexcept
(function specifier)
nullptr
override
static
(class member specifier)
template
this
virtual
(function specifier)
virtual
(base class specifier)
volatile
auto
(until C++11)register
(until C++17)static
extern
thread_local
(since C++11)
#if
: Preprocessor version ofif(...)
#elif
: Preprocessor version ofelse if(...)
#else
: Preprocessor version ofelse
#endif
: Used to end an#if
,#ifdef
, or#ifndef
defined()
: Returns true if the macro is defined#ifdef
: Same as#if defined(...)
#ifndef
: Same as#if !defined(...)
#define
: Defines a text macro. See here for full explanation, including macro functions and predefined macros.#undef
: Un-defines a text macro#include
: Includes a source file#line
: Changes the current file name and line number in the preprocessor#error
: Prints an error message and stops compilation#pragma
: Non-standard, used instead of header guards (#ifndef HEADER_H
...)