The assignment operator (=
) in C++ is a fundamental tool for object-oriented programming, allowing objects to be assigned values after their creation. When working with user-defined classes, it's often necessary to provide a custom implementation of the assignment operator to ensure proper resource management and deep copying of data members. This topic explores various aspects of the assignment operator in class construction.
#include <iostream>
#include <cstring>
class String {
private:
char* data;
size_t length;
public:
String(const char* str = "") : length(strlen(str)) {
data = new char[length + 1];
strcpy(data, str);
}
~String() {
delete[] data;
}
// Copy assignment operator
String& operator=(const String& other) {
if (this != &other) {
delete[] data;
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
return *this;
}
void print() const {
std::cout << data << std::endl;
}
};
int main() {
String s1("Hello");
String s2;
s2 = s1; // Assignment operator called
s1.print(); // Output: Hello
s2.print(); // Output: Hello
return 0;
}
This example demonstrates a basic implementation of the assignment operator for a simple String
class:
String
class manages a dynamically allocated character array.operator=
) is overloaded to perform a deep copy of the string data.*this
) to allow chaining of assignments.#include <iostream>
#include <utility>
class Resource {
private:
int* data;
size_t size;
public:
Resource(size_t n = 0) : size(n), data(n ? new int[n]() : nullptr) {}
~Resource() {
delete[] data;
}
// Copy assignment operator
Resource& operator=(const Resource& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new int[size];
std::copy(other.data, other.data + size, data);
}
return *this;
}
// Move assignment operator
Resource& operator=(Resource&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
void print() const {
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
int main() {
Resource r1(5);
Resource r2;
// Copy assignment
r2 = r1;
// Move assignment
Resource r3;
r3 = std::move(r1);
r2.print(); // Output: 0 0 0 0 0
r3.print(); // Output: 0 0 0 0 0
r1.print(); // Output: (empty, as r1 has been moved from)
return 0;
}
This example showcases both copy and move assignment operators:
Resource
class manages a dynamically allocated integer array.noexcept
to indicate that it doesn't throw exceptions, which can be important for optimizations and exception safety guarantees.main
function, both copy and move assignments are demonstrated.#include <iostream>
#include <string>
class Animal {
protected:
std::string name;
public:
Animal(const std::string& n = "") : name(n) {}
Animal& operator=(const Animal& other) {
if (this != &other) {
name = other.name;
}
return *this;
}
virtual void speak() const {
std::cout << name << " makes a sound." << std::endl;
}
};
class Dog : public Animal {
private:
std::string breed;
public:
Dog(const std::string& n = "", const std::string& b = "") : Animal(n), breed(b) {}
Dog& operator=(const Dog& other) {
if (this != &other) {
Animal::operator=(other); // Call base class assignment operator
breed = other.breed;
}
return *this;
}
void speak() const override {
std::cout << name << " the " << breed << " barks." << std::endl;
}
};
int main() {
Dog d1("Buddy", "Labrador");
Dog d2;
d2 = d1; // Assignment operator called
d1.speak(); // Output: Buddy the Labrador barks.
d2.speak(); // Output: Buddy the Labrador barks.
return 0;
}
This example demonstrates the assignment operator in a class hierarchy:
Animal
base class has a simple assignment operator that copies the name
member.Dog
derived class extends the assignment operator to handle its additional breed
member.Animal::operator=(other)
to ensure proper copying of base class members.The assignment operator is a crucial component in C++ class design, especially when dealing with resource management. Key points to remember:
*this
to allow chaining of assignments.noexcept
when possible for optimization and exception safety.By properly implementing assignment operators, you ensure that your classes behave correctly and efficiently when objects are assigned new values, contributing to robust and maintainable C++ code.