Classes Part 1

Requirements:

  • Linux Distribution
  • g++
  • any text editor

My Setup:

  • Debian 10
  • g++ version 6.3.0
  • pluma

In this tutorial, we will be discussing the basics of Classes within C++. Classes are the blueprints that are used to describe an object within object-oriented programming. Classes define how an object acts as well as its properties. Each of its properties contain “access specifiers”. Access specifiers can be either: private, public, or protected. By default, the properties of an object are private. Unlike structs, whose access specifiers are public by default. Within C++, structs and classes are the same with that one difference. Structs are “POD-types” or Plain-Old-Data. POD-Types is a class (whether defined with the keyword struct or the keyword class) without constructors, destructors, and virtual members functions.To declare a class, you must use the class keyword as such:

class foo{
  private:
  //private members here
  public:
  //public members here
};

Rule of Five:

There is a rule of thumb in C++ called the “Rule of Five”, which is used for building “exception-safe” code and formalizing rules on resource management. Originally, it was a rule of three. C++11 introduced move semantics and two more items have added to the rule. This rule claims if a class has one of the following , then the class should have all.

1. Destructor
2. Copy assignment operator
3. Copy constructor
4. Move assignment operator
5. Move constructor

So what exactly does this all mean and how do you implement this? Lets start by saying this. Every class that contains member variables should have a constructor. A constructor is a special function that initializes variables within the object it is creating. Looking back at the example, lets create a
couple member variables and constructor.

class foo{
  private:
  int _bar;
  int _baz;
  public:
  foo(int bar, int baz):_bar(bar),_baz(baz){}
  ~foo(){}
};

The function which is the class name, in this example, has two parameters because the class contains two private member variables. If these variables are externally modifiable, also add setters. On the other hand, if it will be read externally, you should create getters as well. The colon after the function name is called a member initialization list. What it does is inserts the arguments into the specified variables of the object you are creating. The ~foo() function is a destructor which is called when the object is de-allocated . When you work with pointers as member variables, you may need to de-allocate the pointer to free its memory from within the destructor. An example of how I set up my getters and setters:

class foo{
  private:
  int _bar;
  int _baz;
  public:
  foo(int bar, int baz):_bar(bar),_baz(baz){}
  ~foo(){}

  int Bar() const {return _bar;}
  int Baz() const {return _baz;}
  int getBar() {return bar;}
  int getBaz() {return baz;}

  void setBar(int bar){ this->_bar = bar;}
  void setBaz(int baz){ this->_baz = baz;}

};

Within this example, you see two sets of getters. One when you get a value of a constant , and the other is when you get the value of a non-constant . The const variables are read-only, so modifying them is out of the question. The set functions manipulate the private variables . They use a keyword this , which refers to the current instance of the class. Since this class contains destructor, by rule of five, it also needs the others, so lets implement those:

class foo{
  private:
  int _bar;
  int _baz;
  public:
  foo(int bar, int baz):_bar(bar),_baz(baz){} // parameterized constructor
  // copy constructor
  foo(const foo & other):_bar(other._bar), _baz(other._baz){}
  //copy assignment operator
  foo & operator=(const foo & other){
    this->_bar = other._bar; //assign the current objects member variables to
    this->_baz = other._baz; //the copied object
    return *this;
  }
  //move constructor
  foo(foo && other):_bar(other._bar), _baz(other._baz){
  other._bar = 0; //set the other member variables to 0
  other._baz = 0;
  }
  //move assignment operator
  foo & operator=(foo && other){
  this->_bar = other._bar;  //move the other member variables to the current
  this->_baz = other._baz;  //object
  other._bar = 0;           //set the other member variables to 0
  other._baz = 0;
  return *this;
  }

  ~foo(){}

  int Bar() const {return _bar;}
  int Baz() const {return _baz;}
  int getBar() {return bar;}
  int getBaz() {return baz;}

  void setBar(int bar){ this->_bar = bar;}
  void setBaz(int baz){ this->_baz = baz;}

};

Leave a Reply