Declaring Objects in C++

What is an Object?

An object is an instance of a class. When you declare an object, you’re creating a variable of the class type that has its own memory space for storing the data members defined in the class.

Basic Object Declaration Syntax

ClassName objectName;

This creates an object named objectName of the class ClassName.

Different Ways to Declare Objects

1. Simple Declaration

class Student {
public:
    string name;
    int rollNumber;
};

int main() {
    Student student1;  // Simple declaration of an object
    return 0;
}

2. Declaration with Initialization (Using Constructor)

class Student {
public:
    string name;
    int rollNumber;
    
    // Constructor
    Student(string n, int r) {
        name = n;
        rollNumber = r;
    }
};

int main() {
    Student student1("John", 101);  // Declaring with initialization
    return 0;
}

3. Dynamic Object Creation (Using Pointers)

class Student {
public:
    string name;
    int rollNumber;
};

int main() {
    Student* studentPtr = new Student;  // Create object dynamically
    
    // Use the object through the pointer
    studentPtr->name = "Alice";
    studentPtr->rollNumber = 102;
    
    // Don't forget to free the memory when done
    delete studentPtr;
    return 0;
}

4. Creating Arrays of Objects

class Point {
public:
    int x, y;
    
    Point() {
        x = 0;
        y = 0;
    }
    
    Point(int a, int b) {
        x = a;
        y = b;
    }
};

int main() {
    // Array of 5 Point objects (using default constructor)
    Point pointsArray[5];
    
    // Initialize specific elements
    pointsArray[0].x = 10;
    pointsArray[0].y = 20;
    
    // Dynamic array of objects
    Point* pointsDynamic = new Point[5];
    pointsDynamic[1].x = 30;
    pointsDynamic[1].y = 40;
    
    // Don't forget to delete the dynamic array
    delete[] pointsDynamic;
    
    return 0;
}

5. Declaration with Uniform Initialization (C++11 and later)

class Rectangle {
public:
    double length;
    double width;
    
    Rectangle(double l, double w) {
        length = l;
        width = w;
    }
};

int main() {
    // Uniform initialization syntax
    Rectangle rect1{5.0, 3.0};
    
    // Also valid
    Rectangle rect2 = {6.0, 4.0};
    
    return 0;
}

Memory Allocation for Objects

When you declare an object, memory is allocated for:

  1. All the data members of the class
  2. The object itself (which may include some overhead)

Member functions are not duplicated for each object. They are stored once in memory and shared by all objects of the class.

class Person {
private:
    string name;  // Memory allocated for each object
    int age;      // Memory allocated for each object
    
public:
    void display() { /* Function code - stored once */ }
    void setAge(int a) { age = a; }
};

int main() {
    Person person1;  // Memory allocated for name and age
    Person person2;  // Separate memory allocated for name and age
    
    // Both person1 and person2 share the same function code
    return 0;
}

Accessing Object Members

Using the Dot Operator (.)

For objects declared directly, use the dot operator to access members:

class Student {
public:
    string name;
    int rollNumber;
    
    void display() {
        cout << "Name: " << name << ", Roll: " << rollNumber << endl;
    }
};

int main() {
    Student s1;
    
    // Accessing data members
    s1.name = "John";
    s1.rollNumber = 101;
    
    // Accessing member function
    s1.display();
    
    return 0;
}

Using the Arrow Operator (->)

For objects created dynamically (using pointers), use the arrow operator:

int main() {
    Student* s2 = new Student;
    
    // Accessing data members through pointer
    s2->name = "Alice";
    s2->rollNumber = 102;
    
    // Accessing member function through pointer
    s2->display();
    
    delete s2;
    return 0;
}

Object Initialization

Objects can be initialized in several ways:

1. Using Constructors

class Circle {
private:
    double radius;
    
public:
    // Default constructor
    Circle() {
        radius = 0.0;
    }
    
    // Parameterized constructor
    Circle(double r) {
        radius = r;
    }
};

int main() {
    Circle c1;         // Uses default constructor
    Circle c2(5.0);    // Uses parameterized constructor
    Circle c3 = 7.5;   // Also uses parameterized constructor
    
    return 0;
}

2. Using Initialization Lists (C++11 and later)

Circle c4 = {};        // Default initialization
Circle c5 = {10.0};    // Initialize with radius 10.0

3. Using Copy Constructor

Circle c6 = c2;        // Creates c6 as a copy of c2
Circle c7(c2);         // Also creates a copy

Special Cases of Object Declaration

1. Declaring const Objects

A const object’s data members cannot be modified after initialization:

class Temperature {
private:
    double celsius;
    
public:
    Temperature(double c) : celsius(c) {}
    
    double getCelsius() const {
        return celsius;
    }
    
    double getFahrenheit() const {
        return celsius * 9.0/5.0 + 32.0;
    }
};

int main() {
    const Temperature freezing(0.0);
    
    // These are allowed because the methods are const
    double c = freezing.getCelsius();
    double f = freezing.getFahrenheit();
    
    // This would cause an error
    // freezing.celsius = 100.0;
    
    return 0;
}

2. Objects as Function Parameters

class Point {
public:
    int x, y;
    
    Point(int a = 0, int b = 0) {
        x = a;
        y = b;
    }
};

// Passing object by value (a copy is made)
void displayByValue(Point p) {
    cout << "Point: (" << p.x << ", " << p.y << ")" << endl;
}

// Passing object by reference (no copy is made)
void displayByReference(const Point& p) {
    cout << "Point: (" << p.x << ", " << p.y << ")" << endl;
}

int main() {
    Point p1(10, 20);
    
    displayByValue(p1);      // Creates a copy of p1
    displayByReference(p1);  // Uses the original p1
    
    return 0;
}

3. Objects as Function Return Types

class Complex {
public:
    double real;
    double imag;
    
    Complex(double r = 0.0, double i = 0.0) {
        real = r;
        imag = i;
    }
};

// Function that returns an object
Complex addComplex(const Complex& a, const Complex& b) {
    Complex result;
    result.real = a.real + b.real;
    result.imag = a.imag + b.imag;
    return result;
}

int main() {
    Complex c1(3.0, 4.0);
    Complex c2(1.0, 2.0);
    
    Complex sum = addComplex(c1, c2);
    
    cout << "Sum: " << sum.real << " + " << sum.imag << "i" << endl;
    
    return 0;
}

Anonymous Objects

You can create objects without names (anonymous objects) for temporary use:

class Message {
private:
    string text;
    
public:
    Message(string t) {
        text = t;
        cout << "Message created: " << text << endl;
    }
    
    ~Message() {
        cout << "Message destroyed: " << text << endl;
    }
};

int main() {
    // Anonymous object - created and destroyed in the same statement
    Message("Hello World");
    
    cout << "After anonymous object" << endl;
    
    return 0;
}

Output:

Message created: Hello World
Message destroyed: Hello World
After anonymous object

Common Errors When Declaring Objects

  1. Forgetting to initialize: Objects may contain garbage values if not initialized
  2. Memory leaks: Not deleting dynamically allocated objects
  3. Using uninitialized pointers: Accessing members through null pointers
  4. Accessing private members: Trying to access private members directly
  5. Object slicing: Losing derived class information when assigning to base class objects

Best Practices

  1. Use constructors for initialization: Always initialize objects properly
  2. Prefer stack allocation: Use dynamic allocation only when necessary
  3. Use smart pointers: Consider using std::unique_ptr or std::shared_ptr instead of raw pointers
  4. Pass large objects by reference: Avoid unnecessary copying
  5. Use const where appropriate: Make objects const when they shouldn’t change

Summary

Declaring objects in C++ is the process of creating instances of classes. Objects can be created on the stack (automatic storage), dynamically on the heap, or as part of other data structures like arrays. Proper initialization through constructors ensures that objects start in a valid state. Understanding the different ways to declare and access objects is fundamental to effective C++ programming.