Hello again! In this video, we're going to look at special member functions. (Yes, it does say special member
functions!)
(Out of the way...) Some functions are special.
These are concerned with the management of objects and their lifetime.
The names are related to the name of the class.
And we don't call these explicitly or we don't usually call them explicitly.
Instead, the compiler will automatically add calls which call these member functions when they're needed.
And we can also, sometimes, get the compiler to create these member functions for us.
So in C++, traditionally, there were four special member functions: the constructor, the copy constructor,
the assignment operator and the destructor.
So let's look at those.
The constructor has the same name as the class, and it'll initialize an object using the arguments.
So the constructor gets called whenever we create a new object.
And the arguments that we pass to the constructor are used to initialize the object.
So for example, if we call the Test constructor, which takes these arguments, this will be called
when the test object is created and it'll initialize the i member with the argument from the function
call and the string member with the string argument.
If we put i equals some argument inside here, then this will be called after the object has been created
and initialized.
So this will create an empty string and then if we assign it in here, that will assign it afterwards.
So that's an extra operation.
So normally you would put it up here instead, which would cause it to be initialized at the point
when the object is created.
In the body of the constructor, you would do things which need to be done after the object has been created.
So if you need to allocate memory for storing some data, you can do that. If you need to connect to
a database or read some information from a file and so on.
The copy constructor is similar to the constructor, but instead of having different arguments, which
represents members of the class, we provide an object of the same class and then the new object is
going to be initialized using the object that we pass to it.
So the copy constructor will always take exactly one argument; it will be passed by reference, and
you might like to think about why that is by reference and not by value.
And it's not to do with efficiency.
The reason is that if you have a copy constructor, which takes its argument by value, that will need
to make a copy of the object and to do that, it will call the copy constructor.
And then that call to the copy constructor will itself need to make a copy and so on.
And you get an infinite recursion of calls to the copy constructor.
So that doesn't work.
So you have to do it by reference.
And normally you would do that by reference to const, because you really don't want to change something
that you are copying.
That's a very bad thing to do.
So again, we can initialize the members in the initializer list.
So this will set i, in the new object, to be equal to i in the object that we pass as argument.
And the same goes for the string.
And then inside the body, we can again perform configuration to set up the object that's just been
created.
The assignment [operator] also takes an existing object, but it is called on an object that already exists.
And it'll assign the object so the values in the target object are the same as the values of the members
in the source object.
Again, it takes one argument, which is a reference to const, usually.
As we said, the most efficient way to pass objects is by reference to const. And it returns a reference
to the assigned object.
And the reason why it does that is that you can chain together assignment statements in C and C++,
So you can say a equals b equals c and that's legal. And returning the assigned-to object is required
to enable that to work.
Some people say that the assignment operator should return a const reference, but that's not actually the
best thing to do.
The built-in types always return a non-contact reference, and you should do this as well.
Generally, whenever you write your own operators, they should work the same way as the ones for built-in
types.
Otherwise, it gets too confusing.
And then when you write your assignment operator, you do whatever is needed to set the members
of your object to have the correct values, so i is going to be the value of i from this source object.
And string.
And then we return this object by reference.
So we have this, which is a pointer to the object that we are called on.
"star this" will dereference it,
so that will be the the actual object.
And then the compiler will return a reference to that.
So it all looks a bit peculiar if you haven't seen it before, but it does work and it is correct.
And it is safe as well, because "this" will always be a valid object for as long as the object exists.
And obviously, the object is not going to be destroyed or deleted.
Well, in the middle of a call.
And then finally, the destructor.
So this is called just before the object is destroyed, before the members of the object are released
in memory.
And you can use this to perform any tidying up which you want to do before the object disappears.
So, for example, if you allocated memory when you created the object, you can release it.
If you have a database connection open, you can close it and so on.
So it's just general tidying up. And it has the same name as the class with this squiggle or tilde
is the technical name in front of it.
OK.
So that's it for this video.
I'll see you next time, but meanwhile, keep coding!