Files
CSCI-1200/lectures/04_classes_II
2025-01-22 12:27:50 -05:00
..
2025-01-22 12:27:50 -05:00

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>

class MyClass {
private:
    std::string name;
public:
    MyClass(const std::string& initName) : name(initName) {}

    MyClass& operator=(const MyClass& other) {
        name = other.name; // Copy data
        return *this;
    }

    void print() const { std::cout << "Name: " << name << std::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?

4.6 Exercises