Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Advanced Class and Object Concepts in C++

Tech 2

Initialization Lists

Overview

Class constructors can initialize member variables through assignment within the function body, but another method is using initialization lists. An initialization list begins with a colon followed by a comma-separated list of member variables, each followed by an initializing expression in parentheses.

Key Points

  1. Reference members and const members must be initialized in the list since they cannot be assigned later.
  2. Custom types without default constructors require explicit initialization via the list.
  3. C++11 allows default values at member declaration; these are used when not specified in the list.
  4. Members are initialized in the order of their declaration, not appearance in the list.
  5. Prefer initialization lists for performance and clarity.

Initialization behavior:

  • Members in the list are initialized accordingly.
  • Others folow these rules:
    • If default value exists: use it.
    • Otherwise:
      • Built-in types: compiler-dependent, often uninitialized.
      • User-defined types: use default constructor if available, otherwise error.

Example Usage

struct Stack {
    Stack();
    ~Stack();
    // Some operations may need runtime checks
};

class MyQueue {
public:
    MyQueue() : head(nullptr), tail(nullptr) {}
    // ...
private:
    Stack* head;
    Stack* tail;
};

Type Conversion

C++ supports implicit conversion from built-in types to class objects via constructors accepting those types.

Adding explicit before the constructor disables this feature.

Implicit conversion creates a temporary object, which can be optimized away by compilers. Temporary objects are const and should be handled with const references or pointers.

C++11 also supports multi-parameter implicit conversions.

Static Members

Static members belong to the class rather than instances:

  1. Must be defined outside the class.
  2. Shared among all instances.
  3. Stored in static memory area.
  4. Static functions lack this pointer.
  5. Can access only static members.

Example implementation counting object creation/destruction:

class Counter {
public:
    Counter() { ++count; }
    Counter(const Counter&) { ++count; }
    ~Counter() { --count; }

    static int get_count() { return count; }

private:
    static int count;
    int data = 0;
};

int Counter::count = 0;

Accessing static members:

Counter obj;
int num = Counter::get_count(); // via class scope
int num2 = obj.get_count();     // via instance

Practical Examples

Limit Object Creation

class Singleton {
public:
    static Singleton* create_stack_object() {
        return new Singleton();
    }

    static Singleton* create_heap_object(int x, int y) {
        Singleton* ptr = new Singleton;
        ptr->x = x;
        ptr->y = y;
        return ptr;
    }

private:
    Singleton() {}
    int x = 1;
    int y = 2;
};

Summation Using Static Members

class Accumulator {
public:
    Accumulator() {
        total += index;
        ++index;
    }

    static int get_total() { return total; }

private:
    static int index;
    static int total;
};

int Accumulator::index = 1;
int Accumulator::total = 0;

class Solution {
public:
    int sum_solution(int n) {
        Accumulator arr[n];
        return Accumulator::get_total();
    }
};

Friend Functions and Classes

Friend declarations grant access to private/protected members:

  1. Friends can be functions or classes.
  2. Declared inside the class with friend keyword.
  3. Not part of the class's interface.
  4. Can access private members direct.
  5. Relationships are one-way and non-transitive.
  6. Reduce encapsulation, so use sparingly.

Nested Classes

A class defined inside another class is called a nested class:

  1. Independent class, restricted by outer class access control.
  2. Automatically friend of the outer class.
  3. Useful when tightly coupled with the outer class.

Example:

class Outer {
public:
    class Inner {
    public:
        Inner(int val = 1) : value(val) {}
        void access_outer(const Outer& o) {
            std::cout << o.data << std::endl;
        }
    private:
        int value;
    };

    Outer(int d = 1) : data(d) {}

private:
    int data;
};

Anonymous Objects

Anonymous objects are created without naming them:

class Temp {
public:
    Temp(int v = 1) : value(v) {}
    Temp(const Temp& t) : value(t.value) {}
    ~Temp() { value = 0; }
    void show() const { std::cout << value << std::endl; }
private:
    int value;
};

// Anonymous object
Temp(5).show();

Anonymous objects have limited lifetimes and must be const when used as references or pointers.

Compiler Optimization During Copying

Modern compilers optimize copy operations to improve performance:

  1. Pass-by-value vs pass-by-reference
  2. Return-by-value vs return-by-reference
  3. Constructor optimizations (NRVO, RVO)

Note: Chained assignments and overloaded operators may prevent optimization.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.