Hello again! In this video, we are going to have an overview of the copy constructor. The copy constructor
is a special member function.
It is actually a specialized version of the constructor.
The constructor gets called when we create a new object, and it can be passed any number and type of
arguments.
It can even be passed
no arguments at all, in which case it is the default constructor.
The copy constructor, on the other hand, can only take one argument, which is an object of the same
class.
So when the new object is created, it will be initialized to have the same values as the other object.
This other object is passed as an argument by reference.
So if we have a Test class, it will take a Test object by reference, and that should usually be a
reference to const, as that is more efficient.
And also, it means you cannot accidentally change the thing that you are copying from.
If we initialize a new object from an existing object, the copy constructor will automatically be called.
So if we have some test1 object which we create and we call the constructor with arguments x and
y, for example. Then if we have a new test2 object, which is initialized from test1, that
will call the copy constructor, and the data in test2 will have the same values as the data members in
test1.
Something that looks a bit confusing at first.
If you have an equals sign in here, but you are creating a new object, that will also call the copy
constructor, because that is not an assignment of an existing object.
It is creating a completely new object.
So test3 will be a new object whose members have the same values as test1.
The main situation where the copy constructor is used is in function calls.
If we pass an argument by value, the called function will have a new object created on its stack, and
that will be a copy of the argument.
So the copy constructor will be invoked there, to make the new object a copy of the argument.
Also see when we return a local variable by value.
The function has a return space where it stores the return value, and the new object will be created
in that return space. Which is a copy of the variable that is being returned.
However, the copy constructor does not get called every time we pass or return something by value.
There are some optimizations that compilers are allowed to do, which will reduce the amount of copying.
And we will look at those later on, in a different video.
So the copy constructor may not always be called when you think it should be.
In C++, there is always an exception!
If we do not actually write a copy constructor for the class, the compiler will generate one for
us. That is called a synthesized copy constructor and this will just call the copy constructor for all
the members.
If you have a member which is an object, it will call the copy constructor for that class.
If you have a member which is a built-in type, it will copy it.
And for the large majority of classes, that will be good enough.
There are occasionally situations where that does not give the right behaviour, and then you need
to write your own copy constructor.
The usual case is when you have a class that manages a resource of some kind. So that could be
allocated memory, a thread object, a database connection.
If you just do a naive copy, then both objects end up owning the same resource, and they are going to
conflict with each other.
So you want to make sure that each object has its own version of the resource. And to do that, the
new object has to acquire the resource for itself, and then initialize it from the object that it is copying.
So we will see an example of that later on.
But for the synthesized copy constructor, if we have a class Test which has two members, an int and
a string, then the compiler will generate a copy constructor, which looks like this.
You cannot actually see it in the code, but it will be there.
So this will be the copy constructor for the class Test.
It will take some Test object by reference to const.
It will initialize the "i" member from the argument's "i" member and the string from the argument's string.
One of these things we are going to do throughout this course is to build up our own string
class. It will be String with a capital "S", so it does not get mixed up with the library string class.
And we will build up this string class as we learn more C++ features. To start off with, this is going to be
very simple, because we do not really know all that many features.
We're going to use a library string as a member and then delegate everything to that.
We are going to have a constructor which will take a library string and initialize our member from
that. The copy constructor
will take an object of the same type by reference. As opposed to the constructor, which took an
object of a different type.
(Different spelling. C++ is case sensitive!) And then in the copy constructor,
we are going to initialize our string member from the string member of the argument. And then we have
a function which is going to print out the data in our string member.
In our main function, we are going to create some objects of our class.
So we are going to use a string literal to initialize it.
Then we call the copy constructor.
Then we call it again, using the syntax with an equals sign.
And then we check that we have the data that we expect.
So let's try this out.
So there we are.
We initialized a string with a library string, "world" and we can print out "world", so that works.
We have initialized our string with the same data, in two different ways.
OK, so that is just the beginning of our string class, with a capital "S". It will get more interesting,
I promise!
But that is all for this video.
I will see you next time.
But meanwhile, keep coding!