1 - Copy Constructors
1 - Copy Constructors
Programming
Mohammad Salman
Dean’s Fellow
(SS) Some insights from the lab
• An object gets implicitly passed to the function that is called
through that object.
TollBooth t1;
t1.show();// compiler sees this as, TollBooth::show(&t1)
(SS) Some insights from the lab
• Within TollBooth::show(), you can access t1’s attributes
just by writing out the names of the attributes.
https://www.learncpp.com/cpp-tutorial/introduction-to-the-copy-constructor/
In the first line, f has been initialized using the provided parameters.
In the second line, a new object is created (fCopy) using an existing object of the same class (f).
• Note that the data of both objects is still independent from one another.
• Changing f’s attributes will not impact fCopy’s attributes and vice versa.
// Pass by reference
Fraction(Fraction& frac)
: m_num{ frac.m_num }, m_den{ frac.m_den } OK (but const is better)
{
}
https://www.learncpp.com/cpp-tutorial/introduction-to-the-copy-constructor/
Why would you ever need
to write your own copy
constructor though?
Similar reason as when you would need to write your own
destructor…
Precursor to the RULE OF THREE
At the moment, the implicit copy ctor will be used.
Attributes of list1 will be copied over to attributes of list2.
What will this result in?
class MyList int main()
{ {
private: MyList list1{ 5 };
double* m_array;
int m_length; {
MyList list2{ list1 };
public: }
int getLength() const { return m_length; }
return 0;
MyList(int length) }
: m_array{ new double[length]{} },
m_length{ length }
{}
Btw, my goal here is to create list2
~MyList() with its own array of doubles, but is
{ a copy of the array of list1.
delete[] m_array;
}
};
At the moment, the implicit copy ctor will be used.
Attributes of list1 will be copied over to attributes of list2.
What will this result in?
~MyList()
{
delete[] m_array;
}
};
As list2 is about to go out of scope, the compiler triggers a call to the dtor for list2. Exit
The array on the heap gets deallocated in the dtor call for list2. animations
But list1’s pointer attribute is left dangling. are enabled
on this slide
• If we write a regular ctor, but do not write a copy ctor, then the
compiler doesn’t provide a regular default ctor, but it will provide an
implicit copy ctor.
• However, if you don’t write a regular ctor, but you do write a copy ctor,
then the compiler will not provide you with an implicit copy ctor, but it
will also not provide you with a regular default ctor.
(SS) Something to keep in mind…
Have I written a regular ctor Have I written What will the compiler provide
(default or otherwise)? a copy ctor? me with?
No No Regular default and copy ctors
Yes No Implicit copy ctor
Yes Yes Nothing
No Yes Nothing
public:
Fraction(int num, int den)
: m_num{num}, m_den{den}
{
}
};
What if I set my regular ctor to private?
Error! Since you wrote your own ctor, the compiler doesn’t provide you with one.
Your own ctor is private. So how can it be called from main().
class Fraction int main()
{ {
private: // Calls the regular constructor
int m_num; Fraction f { 5, 3 };
int m_den;
// Calls copy constructor
// Copy constructor Fraction fCopy { f };
Fraction(const Fraction& frac)
: m_num{ frac.m_num }, return 0;
m_den{ frac.m_den } }
{
}
public:
};
Will this array creation work?
Error! This array is meant to initialize an array of Fractions. That means each element will be a Fraction-type
object.
Your ctor, works with two parameters. So each object in the array should be initialized with two parameters.
You are not doing that…
int main()
{
Fraction f{1000, 333};
class Fraction f.show();
{
private: Fraction fArr[3];
int m_num; for(int i{}; i<3; i++)
int m_den; {
fArr[i].show();
public: }
Fraction(int num, int den)
: m_num{num}, return 0;
m_den{den} }
{}
#include <iostream>
void printString1(const char str[]); For test case 1, the const is not required in
printString1(). For test case 2, it is required.
int main()
{
// Test case 1
char arr[]{ "hello" };
Extension
printString1(arr); Keep main() the same, and change the data type of
str in printString1() to std::string.
// Test case 2 • Try passing by value.
printString1("world"); • Try passing by reference.
• Try passing by const reference.
return 0;
}
A const method ensures that the implicit object (the object through which the method is being called) is considered const within
the function. Consider two situations:
• It is valid to have a non-const object call a const method.
• In this case, this object is assumed const within the method, but not in the scope where it was initialized.
As such, const methods can be called by both const and non-const objects.
However, let’s say you have a method that is non-const. A non-const method allows the implicit object to be modified,
potentially.
• It is valid to have a non-const object call a non-const method.
• In this case, if the programmer wants, they can make modifications to the implicit object within this method.
As such, non-const methods can be called by non-const objects, but not const objects.
Extension to the idea of const
As such, const methods can be called by both const and non-const objects.
As such, non-const methods can be called by non-const objects, but not const objects.
class Fraction
{ int main()
public: {
Fraction(int num, int den) const Fraction PI{ 22, 7 };
: m_num{ num }, m_den{ den } Fraction f1{ 2, 5 };
{
if (m_den == 0) // const methods can be called by both const
m_den = 1; and non-const objects
} f1.print();
PI.print();
void print() const // const method
{ // non-const methods cannot be called by const
std::cout << m_num << '/' << m_den << '\n'; objects.
} f1.update(2, 7);
PI.update(100, 3); // compile-time error
void update(int num, int den) // non-const method
{ return 0;
m_num = num; }
m_den = den;
}
private:
int m_num;
int m_den;
};