Arrays, Pointers and References in C++

C++ supports implementation of array of objects. Below is a simple implementation of array of objects –

#include <iostream>

using namespace std;

class c1{
    int i;
    public:
           c1() { i=0; } // for non-initialized array of objects
           c1(int j) { i=j; } // for initialized array of objects
           
           void get_i() { cout << i << "\n"; }
};

int main()
{
    c1 ob1[3] = { 3, 4, 5}; // initialized array of objects
    c1 ob2[3]; // un-initialized array of objects
    
    int i ;
    
    for(i=0; i<3; i++){
        ob1[i].get_i();
        //cout << "\n";
        ob2[i].get_i();
    }
}

Output:
3     
0 
4 
0 
5 
0 

Note that we polymorphic constructors that acts upon the array, and one of them acts upon the array index and assign it to the class member ‘i’. Notice that the class object prints 0 when the un-initialized array object is passed.

Pointers to Objects

Pointer operations in C++ is similar to that in C. Below is a simple program to illustrate the concept of pointers to objects –

#include <iostream>

using namespace std;

class c1{
    int i;
    
    public:
           int k;
           c1() { i=0; } // for non-initialized array of objects
           c1(int j) { k=j; i=j; } // for initialized array of objects
           
           void get_i() { cout << i << "\n"; }
};

int main()
{
    c1 ob1[3] = { 1,2,3 }; // initialized array of objects
    c1 *p; //pointer to object
    
    int i ;
    
    p = ob1; // copies static address of object array
    
    for(i=0; i<3; i++){
        p->get_i(); // calls class function 
        p++;
    }
    p = & ob1.k; // copies address of class variable
    cout << *p;
    return 0;
}

Output:
1
2
3
3

Type Checking

C++ checks for an int *i; float *j and i = j; assignment and quotes it as error since it checks the type of the two pointers.

The ‘this’ Operator

The ‘this’ pointer points to the object that invoked a member function. Below C++ program illustrates the use of ‘this’ operator.

#include <iostream>

using namespace std;

class power{
    double base;
    int exp;
    double value;
    public:
         power(double b, int e);
         double get_power(){
             return this->value;//could use this operator as shown
         }
};

power::power(double b, int e){
    base = b;
    exp = e;
    value = 1;
    for(; exp> 0; exp--){
        this->value *= base;
    }
}

main(){
    power x(23,6);
    cout << x.get_power();
    return 0;
}

Output:
 1.48036e+08

Pointers to Class Members

Based on specific usage, C++ allows declaring pointers to class members. Below is a simple program that shows declaring pointers to class members.

include <iostream>

using namespace std;

class c1{
    public:
         int val;
         c1 (int i) { val = i; }
         int double_val() { return (val + val); }
};

main(){
    int c1:: *data; // data member pointer
    int (c1:: *func)(); // function pointer
    
    c1 ob1(1), ob2(2);
    int *p3;
    c1 *p1, *p2; //pointers to objects
    
    data = &c1::val;
    
    func = &c1::double_val;
    
    p1 = &ob1;
    p2 = &ob2;
    
    cout << ob1.*data << " " << ob2.*data << "\n"; //accessing class members via pointers
    cout << (ob1.*func)() << " " << (ob2.*func)() << "\n"; // accessing class function via pointers
    
    //Also possible
    cout << p1->*data << " " << p2->*data << "\n";
    cout << (p1->*func)() << " " << (p2 ->*func)() << "\n";
    p3 = &ob1.val; //address of specific val
    
    return 0;
}

Output:

1 2     
2 4   
1 2 
2 4  

Pointers to Derived Types

The pointer to a base class also points to the objects of the derived class, but could only access those members imported from the base. The reverse i.e from derived class to base class is not true. Also incrementing the base pointer will not point to the next object of the derived. Below is a simple C++ program to illustrate the usage of pointers to derived class.

#include <iostream>

using namespace std;

class base{
    int i;
    public:
         void set_i(int n){ i = n; }
         int get_i(){ return i; }
};

class derived : public base{
    int j;
    public:
         void set_j(int n){ j = n; }
         int get_j(){return j;}
};

main(){
    base *bp;
    derived d[3]; // if simply d, next line would be bp = &d;
    bp = d;
    bp->set_i(10);
    //bp->set_j(11);//will cause error
    ((derived *) bp)->set_j(11); // true casting
    
    d[0].set_i(1);
    d[1].set_i(2);
    d[3].set_i(3);
    bp++;//will not point to next derived object
    
    cout << bp->get_i();
    
    return 0;
}

Output:
  11