Lecture
The disadvantage of the previously discussed classes is the lack of automatic initialization of the created objects. For each newly created object, it was necessary to call a function of type set (as for the class complex), or to explicitly assign values to the object data. However, to initialize objects of a class, you can explicitly include a special component function in its definition, called a constructor . The constructor definition format is as follows.
class_name (list_of_parameters) {designer_body_ operators};
The name of this component function according to the rules of the C ++ language must match the name of the class. Such a function is automatically called when it is defined or allocated in memory using the operator new of each class object.
For example:
сomplex (double re1 = 0.0, double im1 = 0.0) {re = re1; im = im1;}
The constructor allocates memory for the object and initializes the data members of the class.
The designer has a number of features:
· For a constructor, the type of the return value is not determined. Even the void type is not valid.
· A pointer to a constructor cannot be determined and therefore it is impossible to get the address of the constructor.
· Constructors are not inherited.
· Constructors cannot be described with the keywords virtual, static, const, mutuable, valatile.
A constructor always exists for any class, and if it is not defined explicitly, it is created automatically. By default, a parameterless constructor and a copy constructor are created. If the constructor is explicitly described, then a default constructor is not created. By default, constructors are created publicly.
There can be several constructors in a class, but only one with default values for parameters. Overloading is most often used to pass arguments to the constructor for initializing member data of a class. A constructor parameter cannot be its own class, but may be a reference to it (T &). Without an explicit indication of the programmer, the constructor is always automatically called when defining (creating) an object. In this case, the constructor without parameters is called. To explicitly call a constructor, two forms are used:
class_name object_name (actual_parameters);
class_name (actual_parameters);
The first form is allowed only with a non-empty list of actual parameters. It provides for calling the constructor when defining a new object of this class:
complex ss (5.9,0.15);
The second form of the call leads to the creation of an object with no name:
complex ss = complex (5.9,0.15);
There are two ways to initialize object data using a constructor. Earlier, we considered the first method, namely the transfer of parameter values to the body of the constructor. The second method involves the use of a list of initializers of this class. This list is placed between the parameter list and the body of the constructor. Each list initializer refers to a specific component and has the form
datname (expression)
Example 1.3.1
class A
{
int i; float e; char c;
public:
A (int ii, float ee, char cc): i (8), e (i * ee + ii), s (cc) {}
. . .
};
Example 1.3.2
Example 1.3.2
// Class “character string”.
#include <string.h>
#include <iostream.h>
class string
{
char * ch; // pointer to text string
int len; // text line length
public:
// constructors
// creates an object - an empty string
string (int N = 80): len (0) {ch = new char [N + 1]; ch [0] = '\ 0';}
// creates an object at the specified string
string (const char * arch) {len = strlen (arch);
ch = new char [len + 1];
strcpy (ch, arch);}
// component functions
// returns a reference to the length of the string
int & len_str (void) {return len;}
// returns a pointer to a string
char * str (void) {return ch;}
. . .
};
Here the string class has two constructors - overloaded functions.
By default, a copy constructor of the form T :: T (const T &) is also created, where T is the name of the class. The copy constructor is invoked whenever a copy is made of objects belonging to a class. In particular, it is called:
a) when the object is passed to the function by value;
b) when constructing a temporary object as the return value of the function;
c) when using an object to initialize another object.
If the class does not explicitly contain a specific copy constructor, then when one of these three situations occurs, a bit-wise copy of the object is performed. Bitmap copying is not adequate in all cases. For such cases, it is necessary to define your own copy constructor. For example, create two string objects.
string s1 (“this is a string”);
string s2 = s1;
Here, the s2 object is initialized by the s1 object by calling the copy constructor, created by the default compiler. As a result, these objects have the same value in the ch fields, that is, these fields indicate the same memory area. As a result, if you delete the s1 object, the area occupied by the string will be freed, but the s2 object also needs it. To avoid such errors, we define our own copy constructor.
string (const string & st)
{len = strlen (st.len);
ch = new char [len + 1];
strcpy (ch, st.ch); }
A constructor with one argument can perform an implicit conversion of the type of its argument to the class type of the constructor.
For example:
class complex
{double re, im;
complex (double r): re (r), im (0) {}
...
};
This constructor implements the representation of the real axis in the complex plane.
You can call this constructor in the traditional way.
complex b (5);
But you can call him and so
complex b = 5;
Here it is necessary to convert a scalar value (type of the constructor argument) to the complex type. This is done by calling the constructor with one parameter. Therefore, a constructor that has one argument does not need to be called explicitly, but you can simply write complex b = 5, which means complex b = complex (3).
User-defined conversion is implicitly applied if it is unique. For example,
class demo {
demo (char);
demo (long);
demo (char *);
demo (int *);
...}
Here, in
demo a = 3;
ambiguity: call demo (char)? or demo (long)?
And in demo a = 0; also ambiguity: call demo (char *), or demo (int *), or demo (char), or demo (int)?
In some cases, you need to specify a constructor that can only be called explicitly. For example,
class string {
char * ch;
int len;
public:
string (int size) {
len = size; ch = new [len + 1]; ch [0] = '\ 0';
};
In this case, an implicit conversion may result in an error. In the case of string, s = 'a'; a string of length int ('a') is created. This is hardly what we wanted.
Implicit conversion can be suppressed by declaring a constructor with the explicit modifier . In this case, the constructor will be called only explicitly. In particular, where the copy constructor is basically necessary, the explicit constructor will not be called implicitly. For example:
class string {
char * ch;
int len;
public:
explicit string (int size);
string (const char * ch);
};
string s1 = 'a'; // Error, no explicit char to string conversion
string s2 (10); // Correct, the string to store 10 characters is an explicit // call to the constructor
string s3 = 10; // Error, no explicit int to string conversion
string s4 = string (10); // That's right, the constructor is called explicitly.
string s5 = ”string”; // Correct, implicit constructor call // s5 = string (“string”)
You can create an array of objects, but the corresponding class should have a default constructor (without parameters).
This is due to the fact that when declaring an array of objects, it is impossible to determine the parameters for the constructors of these objects and the only way to call constructors is to pass them the default parameters.
An array of objects can be initialized either automatically by the default constructor, or by explicitly assigning values to each element of the array.
class demo {
int x;
public:
demo () {x = 0;}
demo (int i) {x = i;}
};
void main () {
class demo a [20]; // call the constructor without parameters (by default)
class demo b [2] = {demo (10), demo (100)}; // explicit assignment
When declaring an array of objects, it is impossible to determine the parameters for the constructors of these objects and the only way to call constructors is to transfer the default parameters to them. Thus, in order to create an array of objects, the corresponding class must have a default constructor. You can reduce the number of constructors if you specify a constructor with default arguments. He will be the default constructors.
Dynamic memory allocation for an object makes it necessary to free this memory when an object is destroyed. For example, if an object is formed as local inside a block, then it is advisable that when the block exits, when the object ceases to exist, the memory allocated for it is returned. It is desirable that the release of memory occurs automatically. Such an opportunity is provided by a special class component - the class destructor . Its format is:
~ class_name () {destructor body_ operators};
The name of the destructor coincides with the name of its class, but is preceded by the symbol “~” (tilde).
The destructor has no parameters and no return value. The call to the destructor is performed implicitly (automatically) as soon as the class object is destroyed.
For example, when going outside the definition domain or when calling the delete operator for a pointer to an object.
string * p = new string (“string”);
delete p;
If the destructor is not explicitly defined in the class, the compiler generates a default destructor that simply frees the memory occupied by the object data. In cases where it is necessary to release other memory objects, for example, the area pointed to by ch in the string object, it is necessary to define the destructor explicitly: ~ string () {delete [] ch;}
As well as for the constructor, the pointer to the destructor cannot be defined.
Comments
To leave a comment
C ++ (C plus plus)
Terms: C ++ (C plus plus)