12 KiB
Lecture 4 --- Classes II: Copy Constructor, Assignment Operator, Destructor, and Non-member Operators
4.1 Member Initializer List in C++
A member initializer list is a special syntax in C++ that allows class members to be initialized directly before the constructor body executes. It is used in the constructor definition, right after the parameter list and before the body of the constructor.
Syntax
ClassName(parameter_list) : member1(value1), member2(value2), ... {
// Constructor body (optional, can be empty)
}
Example
#include <iostream>
#include <string>
class MyClass {
private:
std::string name;
public:
// Constructor with member initializer list
MyClass(const std::string& initName) : name(initName) {}
void display() const {
std::cout << "Name: " << name << std::endl;
}
};
int main() {
MyClass obj("Alice");
obj.display(); // Output: Name: Alice
return 0;
}
4.2 Copy Constructor
- A copy constructor is a constructor which is used to create a new object as a copy of an existing object of the same class.
- Copy constructors get called when you create a new object by copying an existing object using the assignment operator (=), or when you pass an object by value to a function.
Copy Constructor Syntax
ClassName(const ClassName& other);
Copy Constructor Example
#include <iostream>
class MyClass {
private:
int value;
public:
// Constructor
MyClass(int val) : value(val) {}
// Copy Constructor
MyClass(const MyClass& other) {
value = other.value;
std::cout << "Copy Constructor Called!" << std::endl;
}
void display() const {
std::cout << "Value: " << value << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = obj1; // Copy constructor is called here
obj2.display(); // Output: Value: 10
return 0;
}
4.3 Assignment Operator
- The assignment operator (=) is used to copy the values from one object to another after both objects have been created.
Assignment Operator Syntax:
ClassName& operator=(const ClassName& other);
Assignment Operator Example:
#include <iostream>
#include <string>
using namespace std;
class MyClass {
private:
string name; // Using a standard string (no pointers)
public:
MyClass(const string& initName) : name(initName) {}
MyClass& operator=(const MyClass& other) {
name = other.name; // Copy data
return *this;
}
void print() const { cout << "Name: " << name << endl; }
};
int main() {
MyClass obj1("Object1");
MyClass obj2("Object2");
obj1 = obj2; // Assignment operator invoked
obj1.print(); // Output: Name: Object2
return 0;
}
All C++ class objects have a special pointer defined called this which simply points to the current class object, and the expression *this is a reference to the class object.
Assignment operators of the form:
obj1 = obj2;
are translated by the compiler as:
obj1.operator=(obj2);
- Cascaded assignment operators of the form:
obj1 = obj2 = obj3;
are translated by the compiler as:
obj1.operator=(obj2.operator=(obj3));
- Therefore, the value of the assignment operator (obj2 = obj3) must be suitable for input to a second assignment operator. This in turn means the result of an assignment operator ought to be a reference to an object.
Note: In C++, the assignment operator is used for assignment after an object has already been created. And because of that, the following two code snippets behave differently.
myClass A = B;
This one line will invoke the copy constructor, rather than the assignment operator. And this behavior is called copy initialization.
myClass A;
A = B;
These two lines will: the first line creates the object A, and the second line invokes the assignment operator.
4.4 Destructor (the “constructor with a tilde/twiddle”)
A destructor is a special member function automatically called when an object goes out of scope or is explicitly deleted.
Destructor Syntax
~ClassName();
Destructor Example
#include <iostream>
class MyClass {
public:
MyClass() { std::cout << "Constructor called" << std::endl; }
~MyClass() { std::cout << "Destructor called" << std::endl; }
};
int main() {
MyClass obj1; // Constructor called
MyClass obj2; // Constructor called
// Destructor will be called automatically at the end of scope
return 0;
}
Question: in the above example, obj1's destructor or obj2's destructor, which one gets called first?
4.5 Overloading operator<< in C++
Purpose
The operator<< is commonly overloaded to enable custom objects to be output using streams such as std::cout.
Example
#include <iostream>
#include <string>
class Person {
private:
std::string name;
int age;
public:
// Constructor
Person(const std::string& name, int age) : name(name), age(age) {}
// Public getters
std::string getName() const { return name; }
int getAge() const { return age; }
};
// Non-member function
std::ostream& operator<<(std::ostream& os, const Person& person) {
os << "Name: " << person.getName() << ", Age: " << person.getAge();
return os;
}
int main() {
Person p("Alice", 30);
std::cout << p << std::endl; // Output: Name: Alice, Age: 30
return 0;
}
Question: Can we overload this operator as a member function?