© Mikael Olsson 2018
Mikael OlssonC++17 Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-3600-0_13

13. Constructors

Mikael Olsson1 
(1)
Hammarland, Finland
 

In addition to fields and methods, a class can contain a constructor. This is a special kind of method used to construct, or instantiate, the object. It always has the same name as the class and does not have a return type. To be accessible from another class, the constructor needs to be declared in a section marked with the public access modifier .

class MyRectangle
{
 public:
  int x, y; MyRectangle();
};
MyRectangle::MyRectangle() { x = 10; y = 5; }

When a new instance of this class is created, the constructor method will be called, which in this case assigns default values to the fields.

int main()
{
  MyRectangle s;
}

Constructor Overloading

As with any other method, the constructor can be overloaded. This will allow an object to be created with different argument lists .

class MyRectangle
{
 public:
  int x, y;
  MyRectangle();
  MyRectangle(int, int);
};
MyRectangle::MyRectangle() { x = 10; y = 5; }
MyRectangle::MyRectangle(int a, int b) { x = a; y = b; }

With the two constructors defined here, the object can be initialized either with no arguments, or with two arguments used to assign the fields.

// Calls parameterless constructor
MyRectangle r;
// Calls constructor accepting two integers
MyRectangle t(2,3);

C++11 added the ability for constructors to call other constructors. Using this feature, the parameterless constructor created earlier is redefined here to call the second constructor.

MyRectangle::MyRectangle() : MyRectangle(10, 5);

This Keyword

Inside the constructor, as well as in other methods belonging to the object—so called instance methods—a special keyword called this can be used. This is a pointer to the current instance of the class. It can be useful if, for example, the constructor’s parameter names are the same as the field names. The fields can then still be accessed by using the this pointer, even though they are overshadowed by the parameters .

MyRectangle::MyRectangle(int x, int y)
{
  this->x = x;
  this->y = y;
}

Field Initialization

As an alternative to assigning fields inside the constructor, fields may also be assigned by using the constructor initialization list. This list starts with a colon after the constructor parameters, followed by calls to the field’s own constructors. This is actually the recommended way of assigning fields through a constructor, because it gives better performance than assigning the fields inside the constructor .

MyRectangle::MyRectangle(int a, int b) : x(a), y(b) {}

Fields can also be assigned an initial value in their class definition, a convenient feature that was added in C++11. This value is automatically assigned when a new instance is created, before the constructor is run. As such, this assignment can be used to specify a default value for a field that may be overridden in the constructor.

class MyRectangle
{
 public:
  int x = 10;
  int y = 5;
};

Default Constructor

If no constructors are defined for a class, the compiler will automatically create a default parameterless constructor when the program compiles. Because of this, a class can be instantiated even if no constructor has been implemented. The default constructor will only allocate memory for the object. It will not initialize the fields. In contrast to global variables, fields in C++ are not automatically initialized to their default values. The fields will contain whatever garbage is left in their memory locations until they are explicitly assigned values .

Destructor

In addition to constructors, a class can also have an explicitly defined destructor. The destructor is used to release any resources allocated by the object. It is called automatically before an object is destroyed, either when the object passes out of scope or when it is explicitly deleted for objects created with the new operator. The name of the destructor is the same as the class name, but preceded by a tilde (~). A class may only have one destructor and it never takes any arguments or returns anything.

class Semaphore
{
 public:
  bool *sem;
  Semaphore()  { sem = new bool; }
  ~Semaphore() { delete sem; }
};

Special Member Functions

The default constructor and the destructor are both special member functions that the compiler will automatically provide for any class that does not explicitly define them. Four other special constructors are the move constructor, the move assignment operator, the copy constructor, and the copy assignment operator. With the C++11 standard came ways of controlling whether to allow these special member functions through the delete and default specifiers. The delete specifier forbids the calling of a function, whereas the default specifier explicitly states that the compiler-generated default will be used.

class A
{
 public:
  // Explicitly include default constructor
  A() = default;
  // Disable move constructor
  A(A&&) = delete;
  // Disable move assignment operator
  A& operator=(A&) = delete;
  // Disable copy constructor
  A(const A&) = delete;
  // Disable copy assignment operator
  A& operator=(const A&) = delete;
};

Object Initialization

C++ provides a number of different ways to create objects and initialize their fields. The following class will be used to illustrate these methods .

class MyClass
{
 public:
  int i;
  MyClass() = default;
  MyClass(int x) : i(x) {}
};

Direct Initialization

The object creation syntax that has been used so far is called direct initialization. This syntax can include a set of parentheses that are used to pass arguments to a constructor in the class. If the parameterless constructor is used, the parentheses are left off.

// Direct initialization
MyClass a(5);
MyClass b;

Value Initialization

An object can also be value initialized. The object is then created by using the class name followed by a set of parentheses. The parentheses can supply constructor arguments or remain empty to construct the object using the parameterless constructor. A value initialization creates only a temporary object, which is destroyed at the end of the statement. To preserve the object, it must either be copied to another object or assigned to a reference. Assigning the temporary object to a reference will maintain the object until that reference goes out of scope .

// Value initialization
const MyClass& a = MyClass();
MyClass&& b = MyClass();

A value initialized object is almost identical to one created by using default initialization. A minor difference is that non-static fields will in some cases be initialized to their default values when using value initialization.

Copy Initialization

If an existing object is assigned to an object of the same type when it is declared, the new object will be copy initialized. This means that each member of the existing object will be copied to the new object .

// Copy initialization
MyClass a = MyClass();
MyClass b = a;

This works because of the implicit copy constructor that the compiler provides, which is called for these kinds of assignments. The copy constructor takes a single argument of its own type, and then constructs a copy of the specified object. Note that this behavior is different from many other languages, such as Java and C#. In those languages initializing an object with another object will only copy the object’s reference, and not create a new object copy.

New Initialization

An object can be initialized through dynamic memory allocation by using the new keyword. Dynamically allocated memory must be used through a pointer or reference. The new operator returns a pointer, so to assign it to a reference it needs to be dereferenced first. Keep in mind that dynamically allocated memory must be explicitly freed once it is no longer needed.

// New initialization
MyClass* a = new MyClass();
MyClass& b = *new MyClass();
// ...
delete a, b;

Aggregate Initialization

There is a syntactical shortcut available when initializing an object called aggregate initialization. This syntax allows fields to be set by using a curly bracket enclosed list of initializers, in the same way as can be done with arrays. Aggregate initialization can only be used when the class type does not include any constructors, virtual functions, or base classes. The fields must also be public, unless they are declared as static. Each field will be set in the order they appear in the class .

// Aggregate initialization
  MyClass a = { 2 }; // i is 2

Uniform Initialization

The uniform initialization was introduced in C++11 to provide a consistent way to initialize types that work the same for any type. This syntax looks the same as aggregate initialization, without the use of the equals sign .

// Uniform initialization
MyClass a { 3 }; // i is 3

This initialization syntax works not just for classes but for any type, including primitives, strings, arrays, and standard library containers such as vectors.

#include <string>
#include <vector>
using namespace std;
int main()
{
  int i { 1 };
  string s { "Hello" };
  int a[] { 1, 2 };
  int *p = new int [2] { 1, 2 };
  vector<string> box { "one", "two" };
}

Uniform initialization can be used to call a constructor. This is done automatically by passing along the proper arguments for that constructor within the curly brackets.

// Call parameterless constructor
MyClass b {};
// Call copy constructor
MyClass c { b };

A class can define an initializer-list-constructor . This constructor is called during uniform initialization and takes priority over other forms of construction, provided that the type specified for the initializer_list template matches the type of the curly bracket enclosed list of arguments. The argument list can be any length but all elements must be of the same type. In the following example, the type of list is int and so the integer list used to construct this object is passed to the constructor. These integers are then displayed using a range-based for loop.

#include <iostream>
using namespace std;
class NewClass
{
 public:
  NewClass(initializer_list<int> args)
  {
    for (auto x : args)
      cout << x << " ";
  }
};
int main()
{
  NewClass a { 1, 2, 3 }; // "1 2 3"
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.137.240