Study resource

Read at your pace, then save it for later.

Unit 7: Advanced Concepts in Classes and Objects in C++

1. Function Definition: Inside vs. Outside the Class

In C++, member functions of a class can be defined either inside the class definition or outside the class definition. Both approaches have their uses and implications.

1.1. Function Definition Inside the Class

When a member function is defined inside the class definition, it is treated as an inline function by default by the compiler. This means the compiler attempts to replace the function call with the actual function body at compile time, potentially improving performance for small functions.

Definition: An inline function is a function that the compiler tries to expand in line at the point of each call rather than being called through a function call mechanism. This can reduce function call overhead.

Example:

class MyClass {
public:
int data;
void setData(int d) { // Defined inside the class
data = d;
}
int getData() { // Defined inside the class
return data;
}
};

Observations:

  • Suitable for short, frequently called functions.
  • Enhances readability as the implementation is close to the declaration.
  • May lead to increased code size if the function is large and called many times, as its body is copied at each call site.

1.2. Function Definition Outside the Class

Member functions can also be declared inside the class but defined outside it. This is typically done to separate the interface (class definition) from the implementation (function definitions), leading to cleaner and more manageable code, especially in larger projects. The scope resolution operator (::) is used to link the function definition to its class.

Important: The scope resolution operator (::) is used to define a member function outside of the class definition or to access a global variable when there is a local variable with the same name.

Example:

class MyClass {
public:
int data;
void setData(int d); // Declared inside
int getData(); // Declared inside
};

// Defined outside the class using scope resolution operator
void MyClass::setData(int d) {
data = d;
}

int MyClass::getData() {
return data;
}

Observations:

  • Better for larger functions, as it prevents code bloat.
  • Improves modularity; the class definition acts as an interface.
  • Functions defined outside the class are not implicitly inline; the inline keyword must be explicitly used if desired.
  • Commonly used when separating class declarations (.h files) from definitions (.cpp files).

2. Private Member Functions

Just like data members, member functions can also be declared with different access specifiers: public, private, or protected. Private member functions are only accessible from within other member functions of the same class.

Definition: A private member function is a member function that can only be called by other member functions of the same class. It cannot be accessed directly by objects of the class from outside.

Purpose and Use Cases:

  • Encapsulation: Private functions help in encapsulating the internal workings of a class. They are often used as "helper" functions that perform specific tasks needed by public member functions.
  • Code Organization: They allow breaking down complex public functions into smaller, more manageable private functions, improving code readability and maintainability.
  • Data Integrity: By restricting access, private functions can enforce specific rules or validations on the class's data members, ensuring data integrity.

Example:

class Calculator {
private:
int validateInput(int num) {
if (num < 0) {
return 0; // Or throw an error
}
return num;
}

public:
int add(int a, int b) {
a = validateInput(a); // Called internally
b = validateInput(b); // Called internally
return a + b;
}
};

// Usage:
// Calculator calc;
// int sum = calc.add(-5, 10); // add calls validateInput internally
// calc.validateInput(10); // ERROR: Private function, cannot be accessed directly

Important Observation: Private member functions promote better design by hiding implementation details and ensuring that the class's state is manipulated only through its public interface.

3. Arrays within the Class

Classes can contain arrays as their member variables. These arrays behave like any other data member but store multiple values of the same type. They can be of any data type, including custom class types.

Concept: An array within a class refers to a data member of the class that is an array type. It allows an object to hold a collection of related data.

Declaration:

Arrays within a class are declared like any other member variable, specifying the type and size of the array.

class Student {
public:
char name[50]; // Array of characters for name
int marks[5]; // Array of integers for marks in 5 subjects

void inputDetails(const char* n, const int m[]) {
// Copy name
for (int i = 0; i < 49 && n[i] != ' '; ++i) {
name[i] = n[i];
}
name[49] = ' ';

// Copy marks
for (int i = 0; i < 5; ++i) {
marks[i] = m[i];
}
}

void displayMarks() {
// Display logic
}
};

Initialization:

Arrays within a class can be initialized through constructors, member functions, or directly in the class definition for C++11 and later (non-static data member initializers).

Accessing Array Elements:

Elements of an array member are accessed using the array subscript operator ([]) through the object, similar to how local arrays are accessed.

// Assuming 'Student s;' is an object
// To set the first mark:
// s.marks[0] = 90;

// To get the name:
// std::cout << s.name << std::endl;

Common Mistake: Forgetting to handle array bounds, leading to buffer overflows or undefined behavior.

4. Memory Allocation of Objects

Understanding how memory is allocated for objects is crucial in C++. When an object is created, memory is primarily allocated for its data members, while member functions are typically stored only once per class.

4.1. Memory for Data Members

Each object of a class gets its own separate copy of all non-static data members. This is why each object can have its own unique state (values for its data members).

  • When an object is created, the memory required to store all its data members (including arrays within the class) is allocated.
  • The size of an object is determined by the cumulative size of all its non-static data members, plus any padding added by the compiler for alignment purposes.
  • Memory for objects can be allocated on the stack (for local objects), on the heap (using new operator for dynamic objects), or in the static/global data segment (for global or static objects).

4.2. Memory for Member Functions

Member functions of a class are typically stored only once in memory, regardless of how many objects of that class are created. They do not occupy memory within each object.

  • When a member function is called, it operates on the specific object that invoked it. This is managed by a hidden pointer called this.
  • The this pointer is implicitly passed to every non-static member function. It points to the object on which the member function was called, allowing the function to access the correct object's data members.
Definition: The this pointer is an implicit pointer available inside every non-static member function of a class. It holds the address of the current object for which the member function is being called.

4.3. Illustrative Example of Object Memory

class Point {
public:
int x;
int y;

void setCoords(int a, int b) {
this->x = a;
this->y = b;
}
void displayCoords() {
// std::cout << "X: " << x << ", Y: " << y << std::endl;
}
};

// If we create two objects:
// Point p1;
// Point p2;

// Memory for p1 will have its own 'x' and 'y'.
// Memory for p2 will have its own 'x' and 'y'.
// The 'setCoords' and 'displayCoords' functions are stored once for the Point class.
// When p1.setCoords(10, 20) is called, 'this' pointer inside setCoords points to p1.
// When p2.setCoords(30, 40) is called, 'this' pointer inside setCoords points to p2.

Key Takeaway: Objects store their unique data, but share the code for their member functions, which are linked to the specific object via the this pointer during execution.


xxx

Did this help you understand better?

Your feedback improves the quality of this resource for everyone.