Array of Objects in C++

What is an Array of Objects?

An array of objects is a collection of multiple objects of the same class, stored in contiguous memory locations. Just like arrays of primitive data types (int, char, etc.), C++ allows you to create arrays where each element is an object of a class.

Declaring an Array of Objects

The basic syntax for declaring an array of objects is:

ClassName arrayName[size];

Where:

  • ClassName is the name of the class
  • arrayName is the name you want to give to the array
  • size is the number of objects in the array

Examples of Declaring Object Arrays

Simple Example

class Student {
private:
    int rollNumber;
    string name;
    
public:
    // Member functions
    void setData(int roll, string n) {
        rollNumber = roll;
        name = n;
    }
    
    void displayData() {
        cout << "Roll Number: " << rollNumber << endl;
        cout << "Name: " << name << endl;
    }
};

int main() {
    // Creating an array of 5 Student objects
    Student students[5];
    
    // Setting data for each student
    students[0].setData(101, "John");
    students[1].setData(102, "Alice");
    students[2].setData(103, "Bob");
    students[3].setData(104, "Emma");
    students[4].setData(105, "David");
    
    // Displaying data for each student
    for (int i = 0; i < 5; i++) {
        cout << "Student " << i+1 << " details:" << endl;
        students[i].displayData();
        cout << endl;
    }
    
    return 0;
}

Initialization of an Array of Objects

There are several ways to initialize an array of objects:

1. Using Default Constructor

If the class has a default constructor (a constructor that takes no arguments), the array elements are initialized using it:

class Point {
private:
    int x, y;
    
public:
    // Default constructor
    Point() {
        x = 0;
        y = 0;
        cout << "Default constructor called" << endl;
    }
    
    void display() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

int main() {
    // This will call the default constructor for each element
    Point points[3];  // Creates 3 points, all initialized to (0,0)
    
    // Display all points
    for (int i = 0; i < 3; i++) {
        points[i].display();
    }
    
    return 0;
}

2. Using Parameterized Constructor

For arrays of objects where the class has a parameterized constructor, you can initialize each element using an initializer list (C++11 and later):

class Rectangle {
private:
    double length;
    double width;
    
public:
    // Parameterized constructor
    Rectangle(double l = 0, double w = 0) {
        length = l;
        width = w;
    }
    
    double area() {
        return length * width;
    }
    
    void display() {
        cout << "Rectangle: " << length << " x " << width;
        cout << ", Area: " << area() << endl;
    }
};

int main() {
    // Initialize array with different values using initializer list
    Rectangle rectangles[3] = {
        Rectangle(5, 3),     // Rectangle with length=5, width=3
        Rectangle(4, 4),     // Rectangle with length=4, width=4
        Rectangle(7, 2)      // Rectangle with length=7, width=2
    };
    
    // Display all rectangles
    for (int i = 0; i < 3; i++) {
        rectangles[i].display();
    }
    
    return 0;
}

3. Initialization After Declaration

You can also initialize objects after declaration by calling methods or using operators:

class Complex {
private:
    double real;
    double imag;
    
public:
    // Default constructor
    Complex() {
        real = 0;
        imag = 0;
    }
    
    // Set values
    void set(double r, double i) {
        real = r;
        imag = i;
    }
    
    void display() {
        cout << real;
        if (imag >= 0) {
            cout << " + " << imag << "i" << endl;
        } else {
            cout << " - " << -imag << "i" << endl;
        }
    }
};

int main() {
    // Declare array of 3 Complex objects
    Complex numbers[3];
    
    // Initialize each object after declaration
    numbers[0].set(2.5, 3.7);
    numbers[1].set(1.1, -4.2);
    numbers[2].set(7.0, 0);
    
    // Display all complex numbers
    for (int i = 0; i < 3; i++) {
        numbers[i].display();
    }
    
    return 0;
}

Memory Allocation in an Array of Objects

When you create an array of objects, memory is allocated contiguously for all objects in the array. The total memory allocated is:

Total memory = Size of one object × Number of objects in the array

Each element in the array is a complete object with its own copy of data members (but they share the same member functions).

Accessing Elements in an Array of Objects

You can access individual objects in the array using array indexing, and then access their members using the dot operator:

// Accessing data members
students[2].rollNumber = 103;  // Directly accessing (if public)

// Accessing member functions
students[2].setData(103, "Bob");  // Using member function
students[2].displayData();        // Calling display function

Loop Processing with an Array of Objects

Arrays of objects are often processed using loops:

For Loop

// Processing all elements with a for loop
for (int i = 0; i < size; i++) {
    students[i].displayData();
}

Range-Based For Loop (C++11 and later)

// Using range-based for loop (C++11 and later)
for (Student& stud : students) {
    stud.displayData();
}

Dynamic Arrays of Objects

You can also create arrays of objects dynamically using the new operator:

// Creating a dynamic array of 10 Student objects
Student* dynamicStudents = new Student[10];

// Using the dynamic array
dynamicStudents[0].setData(201, "Michael");
dynamicStudents[1].setData(202, "Sarah");

// Don't forget to delete the array when done
delete[] dynamicStudents;

Two-Dimensional Arrays of Objects

You can also create two-dimensional arrays of objects:

// 2D array: 3 rows × 2 columns of Point objects
Point grid[3][2];

// Access elements
grid[0][0].setCoordinates(1, 1);
grid[2][1].display();

// Process all elements with nested loops
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
        grid[i][j].display();
    }
}

Advanced Example: Array of Objects with Constructor Parameters

Here’s a more complete example showing an array of objects with a parameterized constructor:

#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    string author;
    int pages;
    double price;
    
public:
    // Default constructor
    Book() {
        title = "Unknown";
        author = "Unknown";
        pages = 0;
        price = 0.0;
    }
    
    // Parameterized constructor
    Book(string t, string a, int p, double pr) {
        title = t;
        author = a;
        pages = p;
        price = pr;
    }
    
    // Display book details
    void display() {
        cout << "Title: " << title << endl;
        cout << "Author: " << author << endl;
        cout << "Pages: " << pages << endl;
        cout << "Price: $" << price << endl;
    }
    
    // Getter for price
    double getPrice() {
        return price;
    }
};

int main() {
    // Array of 5 Book objects with initialization
    Book library[5] = {
        Book("The Great Gatsby", "F. Scott Fitzgerald", 180, 12.99),
        Book("To Kill a Mockingbird", "Harper Lee", 281, 14.50),
        Book("1984", "George Orwell", 328, 10.75),
        Book("Pride and Prejudice", "Jane Austen", 432, 9.99),
        Book("The Hobbit", "J.R.R. Tolkien", 366, 15.25)
    };
    
    // Display all books
    cout << "Library Catalog:" << endl;
    cout << "================" << endl;
    for (int i = 0; i < 5; i++) {
        cout << "Book " << (i+1) << ":" << endl;
        library[i].display();
        cout << endl;
    }
    
    // Find the most expensive book
    int mostExpensiveIndex = 0;
    for (int i = 1; i < 5; i++) {
        if (library[i].getPrice() > library[mostExpensiveIndex].getPrice()) {
            mostExpensiveIndex = i;
        }
    }
    
    cout << "The most expensive book is:" << endl;
    library[mostExpensiveIndex].display();
    
    return 0;
}

Practical Applications of Arrays of Objects

Arrays of objects are useful in many real-world applications:

  1. School Management Systems: Array of Student objects
  2. Library Systems: Array of Book objects
  3. Banking Applications: Array of Account objects
  4. Game Development: Array of Character, Enemy, or Item objects
  5. Inventory Systems: Array of Product objects
  6. Weather Data: Array of WeatherReading objects

Common Errors and Pitfalls

  1. Forgetting Default Constructor: If you declare an array without initialization and your class has no default constructor, you’ll get a compilation error.
  2. Memory Leaks: Not deleting dynamically allocated arrays.
  3. Out-of-Bounds Access: Accessing elements beyond the array size.
  4. Shallow Copying: Be careful with classes that manage resources (pointers) when creating arrays, as default copying might lead to problems.

Best Practices

  1. Use Standard Containers: For most applications, consider using std::vector or std::array instead of raw arrays for better safety and flexibility.
  2. Prefer Stack Allocation: When the array size is known and small, prefer stack allocation over dynamic allocation.
  3. Initialize All Elements: Make sure all array elements are properly initialized.
  4. Range Checking: Always check array bounds before accessing elements.
  5. Consider Object Size: Be cautious with arrays of large objects, as they can consume a lot of memory.

Summary

Arrays of objects in C++ allow you to create collections of related objects of the same class. They combine the efficiency of arrays with the power of object-oriented programming. You can initialize them using constructors, process them with loops, and access individual objects and their members using array indexing and the dot operator. For more dynamic scenarios, consider using standard library containers like std::vector which offer more flexibility and safety than raw arrays.