Month: November 2014

Constructors, Destructors, and Member Functions in C++

Since C++ is a superset of C, we can use functions in C++ in the same way that we use them in C. While this is great and all, let’s focus on functions within the OOP paradigm.

The simplest way to attach a function to an object is to include the function in the description of the class. Functions can be placed in either the public, protected, or private sections of a class.

#include <iostream>
#include <cmath>

using namespace std;

class Square{
    private:
           double _dSide;
    protected:
           double diagonal(){
            return _dSide * sqrt(2);
           }
    public:
           Square(double paramSide = 0.0) { _dSide = paramSide;}
           double area(){ return _dSide * _dSide; }
           double perimeter() { return _dSide * 4; }
};

int main(void){
    //instantiate object of class
    //square
    Square objSq(7);
    cout << "square has a perimeter of : " << objSq.perimeter() << endl;
    cout << "square has an area of : " << objSq.area() << endl;

    return 0;

}

Functions that are part of a class are called member functions. The most ubiquitous member function is the constructor, which creates and initializes an instance of an object of a class. This initialization can use default values or assign no values whatsoever.

A constructor function for a class must have the same name as the name of the class. A constructor function cannot have any return value, not even void. If no constructor is specified, then the compiler will provide a public default constructor. Of particular gravitas is the fact that constructors cannot be inherited from a base class, although we can call a base constructor from the derived class.

The most common mechanism for removing objects from memory is the destructor member function. The notation for a desctructor function is to precede the name of the class with a tilde symbol. Like a constructor function, a destructor cannot have a return value. Destructor functions, unlike constructors, cannot take a

#include <iostream>

using namespace std;

class CDynamicIntArray{

    private:
        int *_iArrPtr;
        int *_iPtrEnd;
        int *_iPtrStart;
    public:
        CDynamicIntArray(int n = 10);
        ~CDynamicIntArray();
        int increment();
        int decrement();
        void reset();
        int getValue();
        void assignValue(int n = 0);
};

//constructor
//create dynamic int array with new
//define bounds of array with poiter arithmetic
CDynamicIntArray::CDynamicIntArray(int n){
    _iArrPtr = new int[n];
    _iPtrEnd = _iArrPtr + n;
    _iPtrStart = _iArrPtr;
}

//destructor
//free up pointers
CDynamicIntArray::~CDynamicIntArray(){
    _iArrPtr = _iPtrStart;
    delete [] _iArrPtr;
}

int CDynamicIntArray::increment(){
    if((_iArrPtr + 1) < _iPtrEnd){
        return *(++_iArrPtr);
    } else {
        return 0;
    }
}

int CDynamicIntArray::decrement(){
    //check if still in bounds
    //and return value
    if(((_iArrPtr - 1) < _iPtrStart)==false){
        return *(--_iArrPtr);
    } else {
        return 0;
    }
}

void CDynamicIntArray::reset(){
    _iArrPtr = _iPtrStart;
}

int CDynamicIntArray::getValue(){
    return *_iArrPtr;
}

void CDynamicIntArray::assignValue(int n){
    *_iArrPtr = n;
    if((_iArrPtr+1) < _iPtrEnd){
        _iArrPtr++;
    }
}

int main(void){
    CDynamicIntArray objDynIArr;

    objDynIArr.assignValue(1138);
    objDynIArr.assignValue(128);
    objDynIArr.assignValue(192);
    objDynIArr.assignValue(224);
    objDynIArr.assignValue(240);
    objDynIArr.assignValue(248);
    objDynIArr.assignValue(80386);
    objDynIArr.assignValue(451);
    objDynIArr.assignValue(1999);
    objDynIArr.assignValue(47);

    //won't assign value
    objDynIArr.assignValue(2001);

    objDynIArr.reset();

    cout << objDynIArr.getValue() << endl;
    cout << objDynIArr.increment() << endl;    

    //last two values will be 0
    //as we have passed the bounds of the array
    for(int i = 0; i < 10; i++){
        cout << objDynIArr.increment() << endl;
    }

    return 0;

}

Constructors and destructors behave differently from other member functions, especially in the context of inheritance. When a derived-class variable is created, the constructor for the base class is called first, followed by the constructor for the derived class.

#include <iostream>

using namespace std;

class CBaseClass{
    public:
        CBaseClass(){
            cout << "CBaseClass constructor called." << endl;
        
        }
        ~CBaseClass(){
            cout << "CBaseClass destructor called." << endl;
        }

};

class CDerivedClass : CBaseClass {
    public:
        CDerivedClass(){
            cout << "CDerivedClass constructor called." << endl;
        }
        ~CDerivedClass(){
            cout << "CDerivedClass destructor called." << endl;
        }
};

int main(void){
    CDerivedClass objDerived;
    
    return 0;
}

After the object variable is destroyed, the class destructors are called. The destructor for the derived class is called first, then the destructor for the base class. Nota bene! Derived classes can operate as base classes. Because of this, we should make the destructor for a base class virtual. Normally, the keyword virtual means “call the derived class function instead of the equivalent base class function”, but destructors are a special case. When a virtual destructor is encountered, the destructor of the derived class will be called, and then the desctructor of the base class will be called.

Pointers and References in C++

When a variable is declared, three attributes are associated with it: its name, its type, and its address in memory. As an example, the declaration double dValue; associates the name dValue, the type double, and the address of a location in memory where the value is to be stored. As we can see, the declaration statement provides the type and symbolic name for the value, and it also causes memory to be allocated to store the value and to keep track of the memory location internally.

The value of a variable is accessed via its name, we can access the memory address itself by means of the address operator, &.

#include <iostream>

using namespace std;

int main(void){

    double d = 169.254;
    char c = 't';

    cout << "c = " << c;
    cout << " and is at " << &c << endl;

    cout << "d = " << d;
    cout << " and is at " << &d << endl;

    return 0;

}

We can create pointers in C++ the same as in C. A pointer is a special type of variable that holds an address of another variable. Thus, the value stored in the pointer variable is the address of another variable. We declare a pointer using the * symbol, which is also used to dereference the pointer variable to get at the data stored in the location that it is pointing to.

The pointer variable must have a declared type; this is because different value types use different numbers of bytes and different internal formats for storing numbers.

#include <iostream>

using namespace std;

int main(void){

    int iValue = 42;

    //pointer to int
    int *iPtr;
    
    //assign a memory location
    //to the pointer variable
    iPtr = &iValue;

    cout << &iValue << " " << iPtr << endl;

    return 0;

}

We can think of a pointer as a locator, it tells us where we can locate another variable.

To get the value to which the pointer points, we use the dereference operator, *. We can think of the dereference, *,  operator and the address of operator, &, as being inverses of each other.

We can use the pointer to change the value stored in the original value; in C, using pointers is the method by which we persistently modify variables in other functions. To do this, we must use the dereference operator and the assignment operator together.

#include <iostream>

using namespace std;

int main(void){

    int iValue = 404;
    //declare pointer to ivalue
    //using address of operator
    int *iptrValue = &iValue;

    cout << "iValue = " << iValue << endl;
    cout << "*iptrValue = " << *iptrValue << endl << endl;

    cout << "iValue is at " << &iValue << endl;
    cout << "iptrValue points to " << iptrValue << endl << endl;

    //increment has precedence over 
    //dereference     
    (*iptrValue)++;

    cout << "iValue = " << iValue << endl;


    *iptrValue = 4004;

    cout << "iValue = " << iValue << endl;

    return 0;

}

Array names have the unusual property of devolving into pointers. An array name without an index is, in essence, a pointer to the address of the start of the array. The index number specifies the offset from this base address, each offset is arrived at by multiplying the index number by the size of one element in the array.

#include <iostream>

using namespace std;

int main(void){

    int iArray[5] = { 4, 8, 15, 16, 23};

    cout << iArray << endl;
    cout << iArray + 1 << endl;
    cout << iArray + 2 << endl;
    cout << iArray + 3 << endl;    
    cout << iArray + 4 << endl;

    return 0;

}

Although pointers are expressed as integers (in hexadecimal form, usually), they are not integer types. We can, however, apply some integer arithmetic operators to pointers; this is known as pointer arithmetic. For instance, pointers can be incremented and decremented just as integers can. However, the increase or decrease in the pointer’s value is not necessarily one, but rather the size of the memory the pointer’s type occupies.

#include <iostream>

using namespace std;

int main(void){
    
    const int array_bounds = 7;

    int iArray[array_bounds] = {1, 5, 7, 13, 17, 19, 23};

    //end of the array
    int *iPtrArrEnd = iArray + array_bounds;
    int *iPtrArrStart = iArray;

    while(iPtrArrStart < iPtrArrEnd){
        cout << *iPtrArrStart << " at " << iPtrArrStart << endl;
        iPtrArrStart++;
    }
    return 0;

}

One of the main uses for pointers is allocating unnamed memory during runtime, where pointers are the only way to access that memory. In C++, we use the new operator to allocate memory. We tell new what data type we want memory for, new finds a block of the appropriate size, and then returns the address of the block. We then assign this address to a pointer.

The delete operator reverses the action of the new operator, it frees the allocated memory. The delete operator should only be applied to pointers that have been allocated by the new operator.

#include <iostream>

using namespace std;

int main(void){

    int * iPtr = new int;
    double * dPtr = new double;

    *iPtr = 1138;
    *dPtr = 255.255;

    cout << *iPtr << " " << *dPtr << endl;

    delete iPtr;
    delete dPtr;

    return 0;

}

Note that in the unlikely event that there is not enough memory for new to allocate a block of the required size, the new operator will return 0.

A reference is an alias, a synonym for another variable. A reference, unlike a pointer, must be assigned another variable when it is declared.  We use the address operator, &, to assign a reference just as with pointers; however, we append the address operator not to the original variable, but to the variable that is the referring to the original variable.The original variable and the reference thus act as two different names for the same memory location.

#include <iostream>

using namespace std;

int main(void){

    int i = 73;
    //r is a reference to i
    int &r = i;

    cout << "i = " << i << endl;
    cout << "r = " << r << endl;

    i = 47;

    cout << "i = " << i << endl;
    cout << "r = " << r << endl;

    return 0;

}

Function Templates in C++

We can use a function template to define a function using an abstract data type and then use that template to create functions that use specific data types, like double or int. A function template allows us to leave the data type the function works on unspecified, and then we specify the data type when we use the template to create a function.

Let’s start by creating a function template increment that simply adds one to a number passed in by reference. To create a function template, we need to use a name to stand n for the data type that will ultimately be used in the function, by convention we will use the name T.

We start a template using the keyword template, followed by greater than and less than signs. Within these signs, we place the keyword typename, followed by the name we want to stand in for the type.

#include <iostream>

template<typename T>
void increment(T &n){
    n++;
}

using namespace std;

int main(void){

    int i = 1701;
    double d = 3.14159;

    cout << i << endl;
    cout << d << endl;

    increment(i);
    increment(d);

    cout << i << endl;
    cout << d << endl;

    return 0;
}

Once the template is defined, we can use it to create functions. Actually, to be more exact, we let the compiler create the functions for us.

It is of course possible to have a template function return a generic value. We can also include arguments of a fixed data type in the argument list of the function we are create a template for.

#include <iostream>

template <typename T>
T decrement(T &n){
    return --n;
}

template <typename T>
T add(T n, int i){
    return n + i;
}



using namespace std;

int main(void){

    int i = 73;
    double d = 255.224;

    cout << i << endl;
    cout << d << endl;
    decrement(i);
    decrement(d);
    cout << i << endl;
    cout << d << endl;
    cout << "d + i = " << add(d, i) << endl;

    return 0;
}

We can overload function templates just as we can overload regular functions. We simply define a number of function templates with different function signatures.

#include <iostream>

template<typename T>
T add(T i, T j);

template<typename T>
T add(T i, T j, T k);

using namespace std;

int main(void){

    cout << add(1138, 8086) << endl;
    cout << add(19.19, 23.16, 103.2339) << endl;    

    return 0;

}

template<typename T>
T add(T i, T j){
    return i + j;
}

template<typename T>
T add(T i, T j, T k){
    return i + j + k;
}

Although the C++ compiler instantiates functions from the function templates for us, we can also create explicit function instantiations as well. To create an explicit function instantiation, we give the data type we want the instantiation to handle, such as int or double.

#include <iostream>

template<typename T>
void swapValues(T &val1, T &val2){
    T tempVal = val1;
    val1 = val2;
    val2 = tempVal;
}

template void swapValues<char>(char &, char &);

using namespace std;

int main(void){

    char a = 'x';
    char b = 'y';

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    swapValues(a, b);

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    return 0;

}

Interested in learning C? Take a look at my book http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M

Derived and Base Classes in C++

We can construct new classes from old classes. The here is to decide what member data and functions in the old class are appropriate for the desired new class.

Formally, the old class is referred to as the base class, and the new class is referred to as the derived class. The derived class inherits from the base class the basic structure and the defined functions, allowing us to reuse code. Inheritance is a cornerstone of C++, and object oriented languages in general.

Let’s create a base class called CRectangle and a derived class called CSquare.

#include <iostream>

using namespace std;

class CRectangle{
private:
    double _dLength;
    double _dWidth;
public:
    CRectangle(double paramL = 0.0, double paramW = 0.0);
    double area() { return (_dLength * _dWidth); }
    double perimeter() { return (2.0 * (_dLength + _dWidth)); }
};

//constructor for CRectangle
CRectangle::CRectangle(double paramL, double paramW){
    _dLength = paramL;
    _dWidth = paramW;
}

//derived class, CSquare
class CSquare : public CRectangle{
private:
    double _dSide;
public:
    CSquare() {_dSide = 0.0;};
    CSquare(double paramSide) : CRectangle(paramSide, paramSide){_dSide = paramSide;};
};

int main(void){
    CRectangle objR1(7, 11);
    CRectangle objR2(42, 3);
    
    CSquare objS1(5.5);
    CSquare objS2(7.9999);
    
    cout << "Area of first rectangle: " << objR1.area() << endl;
    cout << "Perimeter: " << objR1.perimeter() << endl;
    
    cout << "Area of second rectangle: " << objR2.area() << endl;
    cout << "Perimeter: " << objR2.perimeter() << endl;
    
    cout << "Area of first square: " << objS1.area() << endl;
    cout << "Perimeter: " << objS1.perimeter() << endl;
    
    cout << "Area of second square: " << objS2.area() << endl;
    cout << "Perimeter: " << objS2.perimeter() << endl;
    
    return 0;
    
}

When we define CSquare, we begin with line class CSquare : public CRectangle; this line indicates that each public member function for the base class is also public in the derived class. We can then call the CRectangle member functions for CSquare objects.

Next, let’s create a simple example of a stack class, called CStack. A stack is a data structure that operates like a stack of papers in the inbox on a desk – the last paper added to the stack is the first paper taken off the top to be read. We will then create a bounded stack that performs bounds-checking, and called it CBStack. We will use CStack as the base class to create CBStack as a derived class.

//CStack.h
//begin------------------------------------------
#ifndef CSTACK_H
#define    CSTACK_H

class CStack {
protected:
    int iCount;
public:
    CStack(const int size);
    ~CStack(void);
    virtual void push(const int paramItem);
    virtual int pop(void);
private:
    int * _iPtrData;
};

#endif    
//CStack.h
//end--------------------------------------------------


//CStack.cpp 
//begin ---------------------------------------------
#include "CStack.h"
#include "CBStack.h"

CStack::CStack(int paramSize) {
    _iPtrData = new int[paramSize];
    iCount = 0;
}

CStack::~CStack(){
    delete _iPtrData;
}

void CStack::push(const int paramItem){
    _iPtrData[iCount] = paramItem;
    iCount++;
}

int CStack::pop(void){
    return _iPtrData[--iCount];
}

//CStack.cpp
//end-------------------------------------------------


//CBStack.h
//begin---------------------------------
#include "CStack.h"

#ifndef CBSTACK_H
#define    CBSTACK_H

class CBStack : public CStack {
public:
    CBStack(const unsigned int size) : CStack(size), _uiStack_Size(size){};
    virtual int pop();
    virtual void push(const int paramItem);
private:
    const unsigned int _uiStack_Size;
};

#endif    /* CBSTACK_H */

//CBStack.h
//end---------------------------------


//CBStack.cpp
//begin-------------------------
#include "CBStack.h"

int CBStack::pop(void){
    if(iCount >= 0){
        return CStack::pop();
    } else {
        return 0;
    }
} 

void CBStack::push(int paramItem){
    if(iCount < _uiStack_Size){
        CStack::push(paramItem);
    }
}

//CBStack.cpp
//end----------------------------------------


Note that we declared data member iCount to be protected. Data members that are protected are visible to the base class and any derived classes, only.

The virtual keyword, which we have seen above, identifies a member function that can be overridden by a member function in the derived class. If we are using a derived class, than the compiler will look for members in the derived class first, and then the base class.

Some Particulars Concerning Functions in C++

Arguments are passed by value to functions in C. Yes, we can use the address of operator & and pass in a pointer, but note that even in this situation, we are passing the argument by value – it just happens that the value we are passing in is a pointer to the memory location we want to access!

C++ allows for the passing of pointers by value, just as in C. However, there is another method as well, we can use the address operator & to pass the argument by reference. We can also pair the address of operator with the keyword const to make the value passed in by reference immutable within the function.

#include <iostream>

using namespace std;

void exampleOne(int x);
void exampleTwo(int &x);
void exampleThree(const int &x);

int main(void){

    int x = 42;

    exampleOne(x);    
    exampleTwo(x);    
    exampleThree(x);

    return 0;
}

void exampleOne(int x){
    cout << "received :" << x << endl;
    cout << "adding five to x, ";
    x += 5;
    cout << "x now: " << x << endl;
}

void exampleTwo(int &x){
    cout << "received :" << x << endl;
    cout << "adding thirty one to x, ";
    x += 31;
    cout << "x now: " << x << endl;
}

void exampleThree(const int &x){
    cout << "received :" << x << endl;
    cout << "adding twenty seven to x, ";
    cout << "wait... nevermind!" << endl;
}

Note that the implementation of references isn’t exactly specified – it’s left up to the compiler. References are most likely implemented behind the scenes using pointers, which makes passing by reference a form of syntactic sugar. However, there are some key differences between a pointer and a reference. Unlike a C++ reference, a pointer may be null, and it may be reassigned to a new memory address. Also, references need to be initialized when they are defined.

#include <iostream>

using namespace std;

int main(void){

    int x = 404;
    int y = 1138;

    //pointer
    int *xPtr;
    //reference
    int & refX = x;

    cout << "x = " << x << endl;
    //changing the reference changes
    //the original value
    refX++;
    cout << "x = " << x << endl;
    cout << "++refX = " << ++refX << endl;

    xPtr = &x;

    cout << "*xPtr = " << *xPtr << endl;

    xPtr = &y;

    cout << "*xPtr = " << *xPtr << endl;

    return 0;

}

If we declare a function with the qualifier inline before its definition, then it is expanded at every point in the code where it is used, thereby obviating the overhead of a function call and return.

#include <iostream>

using namespace std;

class Dog{
    public:
        inline void bark();
        inline void jump();
};

inline void Dog::bark(){
    cout << "bow wow!!! ";
}

inline void Dog::jump(){
    cout << "(jumps) ";
}

int main(void){

    Dog rufus;

    for(int i = 0; i < 1000; i++){
        rufus.bark();
        rufus.jump();
    }

    return 0;

}

Friend functions are used to allow access to a class by either a different class or a function defined outside the original class. Friend functions do not require that the class using them be related via inheritance. A friend function can have access to the private and protected members of the class.

Friend functions can disrupt the modularity of a class.

Arrays and Functions in C++

Let’s design a function to add the elements in an array.

In C++, as in C, the array name itself is often treated as a de facto pointer. For our function to add the array, we will pass as the first argument the name of the array, and the second argument will be the int bounds of the array.

#include <iostream>

int sumArray(int iArray[], int iBounds);

using namespace std;

int main(void){

    int iNums[] = {4, 8, 15, 16, 23, 42};
    
    int iBounds = sizeof(iNums) / sizeof(int);
    
    cout << "The number of elements in the array is: " << iBounds << endl;
    
    cout << "The sum of the elements is: " << sumArray(iNums, iBounds) << endl;
    
    return 0;
}

int sumArray(int iArray[], int iBounds){
    int iSum = 0;
    for(int i = 0; i < iBounds; i++){
        iSum += iArray[i];
    }
    return iSum;
}

Again, in most contexts C++ treats the name of an array as if it were a pointer, specifically to the first element in the array. If we wish to use pointer syntax in the array’s parameter list, we may do so.

#include <iostream>

using namespace std;

//function overloading
//first function handles c-style strings
//second hands int arrays
void printArray(char *szString);
void printArray(int *iNums, int iBounds);


int main(void){

    char *szText = "El Psy Congroo.";
    char *szText2 = "";
    int iNums[] = {53, 88, 118, 389, 443, 546};
    
    //no need to use reference operator on
    //array indentifiers
    printArray(szText);
    printArray(szText2);
    printArray(iNums, sizeof(iNums) / sizeof(int)); 
    
    return 0;
}

void printArray(char *szString){
    while(*szString!=''){
        cout << *szString << " ";
        szString++;
    }
}

void printArray(int *iNums, int iBounds){
    int i;
    for(i = 0; i < iBounds; i++){
        cout << *(iNums+i) << " "; 
    }
}

We recall here that adding one to a pointer, which includes an array name in this context, in fact adds a value equal to the byte size of the type to which the pointer is pointing. Thus, pointer arithmetic and array subscription are equivalent methods of iterating through a array.

We must explicitly pass the size of the array to the function because sizeof() only yields the size of the pointer, and not the size of the entire array.

#include <iostream>

using namespace std;

void sizeOfArray(int iArray[]);
void sizeOfArray(double *dArray);

int main(void){

    double dArry[] = {4.55, 4.29, 19.99, 21.27};
    int iArry[] = {1138, 47, 8088, 64};
    
    cout << "size of double array in main(): " << sizeof(dArry) << endl;
    sizeOfArray(dArry);
    
    cout << "size of int array in main(): " << sizeof(iArry) << endl;
    sizeOfArray(iArry);
    
    return 0;
}

void sizeOfArray(int iArray[]){
    cout << "sizeof int array (in the user-defined function): " << sizeof(iArray) << endl;
}

void sizeOfArray(double *dArray){
    cout << "sizeof double array (in the user-defined function): " << sizeof(dArray) << endl;
}

Since a function with an array name argument has access to the original array, not a copy, we can use a function call to assign values to the arrays elements. We can use a loop to read successive values into the array, and then utilize a special flag value to indicate the end of input.

#include <iostream>

using namespace std;

int populateArray(int iArray[], int iBounds){
    int i, iValue;
    cout << "Fill the array with positive integer values." << endl;
    cout << "Up to " << iBounds << " separate entries allowed." << endl;
    for(i = 0; i < iBounds; i++){
        cout << "Enter value #" << i + 1 << " (Enter any negative number to finish): ";
        cin >> iValue;
        if(!cin){
            //bad input!
            cin.clear();
            while(cin.get()!='\n'){ continue; }
            cout << "Bad input, returning..." << endl;
            return i;
        }
        else if(iValue < 0){
            return i;
        }
        else {
            iArray[i] = iValue;
        }
    }
}

double arrayAverage(int iArray[], int iBounds){
    int iSum = 0;
    for(int i = 0; i < iBounds; i++){
        iSum += iArray[i];
    }
    return (double)iSum / iBounds;
}

int main(void){

    int iArray[50];
    int iBounds = populateArray(iArray, 50);
    double dAverage = arrayAverage(iArray, iBounds);
    
    cout << "Number of elements in the array: " << iBounds << endl;
    cout << "Average is " << dAverage << endl;
   
    return 0;
}

One problem for us to think about is the function to sum up the elements of the array. What if we accidentally modified the value passed in to the function? For elements passed in by value, it wouldn’t be such a big deal – only the local variable would be incorrect, and the problem would be contained. However, if we are dealing with a value passed in by reference, for example an array, any accidental change we make to it will be permanent.

To guarantee that a function won’t alter the value of the original data structure, we can safeguard the parameter using the keyword const when we define the array.

#include <iostream>

using namespace std;

void displayArray(const double dArr[], int n){
    for(int i = 0; i < n; i++){
        cout << "Element # " << (i + 1) << ": ";
        cout << dArr[i] << endl;
    }
}

void displayReversedArray(const double dArr[], int n){
    for(int i = n - 1; i >= 0; i--){
        cout << "Element # " << (i + 1) << ": ";
        cout << dArr[i] << endl;
    }
}


int main(void){

    double dArray[] = {72.91, 18.01, 54.25, 5.1, 5.48};
    
    displayArray(dArray, sizeof(dArray) / sizeof(double));
    displayReversedArray(dArray, sizeof(dArray) / sizeof(double));
    
    return 0;
}

If you get the chance, please take a look at my C programming book:

Construction in C++

A constructor is a special member function that is automatically invoked whenever an object is created.

A constructor has the same name as the class being defined. It is odd in that it does not have a return type, not even void. The simplest constructors initialize the state of every object created to the same initial state.

Let’s start with a class for representing rational numbers.

#include <iostream>

using namespace std;

class CRational{
    public:
        CRational();
        void display();
    private:
        int _iNum;
        int _iDen;
};

CRational::CRational(){
    _iNum = 0;
    _iDen = 0;
}

void CRational::display(){
    cout << _iNum << " / " << _iDen;
}

int main(){

    CRational exmp;

    exmp.display();

    cout << endl;

    return 0;

}

As we can see in the example above, the constructor is easily recognizable both by the name and the absence of any return type. Our constructor initializes the private data members to 0.

More commonly, we want to provide data to initialize that particular object. Since a constructor is a function, it can take arguments. Although the constructor is not explicitly called, we can pass arguments to the constructor by placing the arguments in a set of parentheses when the variable of the class type is declared.

Let’s revisit the rational number class from before.

#include <iostream>

using namespace std;

class CRational{
    public:
        CRational();
        //parameterized constructor
        CRational(int n, int d);
        void display();
    private:
        int _iNum;
        int _iDen;
};

CRational::CRational(){
    _iNum = 0;
    _iDen = 0;
}

//pass in arguments to the constructor
CRational::CRational(int n, int d){
    _iNum = n;
    _iDen = d;
}

void CRational::display(){
    cout << _iNum << " / " << _iDen;
}

int main(){

    CRational another(42, 6);
    
    another.display();

    cout << endl;

    return 0;

}

If we wish to create an object on the heap and initialize a pointer variable to point to it, we can put the constructor’s arguments after the class name in the call to new.

#include <iostream>
#include <string>

using namespace std;

class CDog{
 public: 
 CDog(string name, string breed, int age);
 void print();

 private:
 string _strName;
 string _strBreed;
 int _iAge;

};

CDog::CDog(string name, string breed, int age){
 _strName = name;
 _strBreed = breed;
 _iAge = age;
}

void CDog::print(){
 cout << _strName << ", " << _strBreed << " (" << _iAge << ")" << endl;
}

int main(void){

 CDog *exmpOne = new CDog("Lucy", "Shih Tzu", 12);

 exmpOne->print();

 return 0;

}

In general, it’s best for all objects to be initialized when they are created. In the even that we do not want to provide the object with any particular arguments, we can specify a default constructor to initialize all the data members to an innocuous value, such as zero.

One option is to define what is called a default constructor, which is simply a constructor that can be called with no arguments. In cases where an object is created but no constructor arguments are supplied, the brackets are also omitted.

Note that the compiler provides a default constructor automatically, but only if we do not define any other constructors. If we define our own constructor, we must also explicitly define a default constructor as well, if we want to be able to initialize an object without any arguments.

We may infer here that it is quite common to provide a class with more that one constructor. The compiler differentiates between constructors via there parameter lists, function overloading, essentially.

#include <iostream>

using namespace std;

class CDate{
    public:
        //default constructor
        CDate();
        //parameterized constructor
        CDate(int day, int month, int year);
        void print();
    private:
        int _iDay;
        int _iMonth;
        int _iYear;
};


CDate::CDate(){
    _iDay = 1;
    _iMonth = 1;
    _iYear = 1970;
}

CDate::CDate(int day, int month, int year){
    _iDay = day;
    _iMonth = month;
    _iYear = year;
}

void CDate::print(){
    cout << _iMonth << "/" << _iDay << "/" << _iYear;
}

int main(void){

    CDate dateOne;
    CDate dateTwo(9, 9, 2001);

    dateOne.print();

    cout << endl;

    dateTwo.print();

    cout << endl;

    return 0;

}

As well as a convenience, constructors provide us with a degree of safety, by making it impossible to instantiate uninitialized objects.

Constructors can neither be inherited, nor can they be declared virtual – which is a good thing. However, we can explicitly call the parent class’s constructor from the derived class’s constructor.

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

class CShape{
 public:
 CShape();
 CShape(int x, int y);
 string location();
 private:
 int _iX;
 int _iY;

};


CShape::CShape(){
 _iX = 100;
 _iY = 100;
}

CShape::CShape(int x, int y){
 _iX = x;
 _iY = y;
}

string CShape::location(){
 stringstream ss;
 ss << "(" << _iX << ", " << _iY << ")";
 return ss.str();
}



class CCircle : public CShape{
 public:
 CCircle(int radius);
 CCircle(int radius, int x, int y);
 double circumference();
 double area();
 private:
 int _iRadius;
 const static double pi;
};

CCircle::CCircle(int radius)
:CShape()
{
 _iRadius = radius;
}

CCircle::CCircle(int radius, int x, int y)
:CShape(x, y)
{
 _iRadius = radius;
}

const double CCircle::pi = 3.14159;

double CCircle::circumference(){
 return 2 * CCircle::pi * _iRadius; 
}

double CCircle::area(){
 return CCircle::pi * _iRadius * _iRadius; 
}

int main(void){
 CCircle cOne(11, 44, 40);
 CCircle cTwo(47);

 cout << "cOne is located at " << cOne.location() << endl;
 cout << "and has a circumference of " << cOne.circumference() << endl;

 cout << "cTwo is located at " << cTwo.location() << endl;
 cout << "and has an area of " << cTwo.area() << endl;
 return 0;
}

Remember, we must create a constructor for each derived class.

Hiding Data in Classes in C++

We can say that the class is the type of the object, much as a cookie cutter determines the shape of the cookie. To instantiate an object of a certain class, we simply declare the object as a variable of the class type.

We can store data in objects via class data members, which are almost exactly like the data members of a structure, with a key difference that we will get to shortly.

#include <iostream>

using namespace std;

class CExample{
    public:
        int A;
        double B;
};

int main(void){
    CExample exmp;
    exmp.A = 47;
    exmp.B = 19.99;

    cout << exmp.A << endl;
    cout << exmp.B << endl;

    return 0;
}

Data and methods inside C++ classes are by default private, which means they are only accessible to code inside the class, emphasizing the data-hiding nature of classes. Class scope works by making members of a class only visible to code inside the class. If we wish to make class members accessible to outside the class, we must use the keyword public.

From outside the class, all public members are visible and all private members are hidden. Protected members are somewhat in between the two; protected members are visible to code in classes that inherit from teh present class.

#include <iostream>
#include <string>

using namespace std;

class CBird{

 //let's make everything visible
 public:
 string strName;
 int iNumSeen;
 int incrementNumSeen(){
 return ++iNumSeen;
 }

};

int main(void){
 CBird bird;
 bird.strName = "bluebird";
 bird.iNumSeen = 5;

 cout << "We have seen " << bird.iNumSeen << " " << bird.strName << "(s)." << endl;
 cout << "Now we have seen " << bird.incrementNumSeen() << " " << bird.strName << "(s)." << endl;

 return 0;
}


We should remember here that a class is a type, with which we can create objects.

In the example above we accessed data directly. Generally speaking, data hiding is a major portion of classes’ raison d’etre, so we should strive to handle data members within the class itself. However, classes are types, so we cannot really store data in the class itself, we must wait until an object is initialized.

We can, however, initialize the data in objects using constructor methods. A constructor method is a method that is run when the object is allocated in memory, at which time we can initialize the object’s state, i.e. its data members. A constructor has the same name as the class and has no return value. Just as with any other method, a constructor can accept one or more arguments.

#include <iostream>
#include <string>


using namespace std;

class CDog{
 public:
 string strName;
 string strBreed;
 CDog(string name, string breed);

};

CDog::CDog(string name, string breed){
 strName = name;
 strBreed = breed;
}

int main(void){

 CDog dog("Fido", "German Shepard");

 cout << dog.strName << " is a " << dog.strBreed << "." << endl;

 return 0;

}

We can use data access methods to enable class data  members to be entirely private. When we make data members private, we can provide access methods to control the access that code outside the object has to the object’s internal data.

#include <iostream>
#include <string>

using namespace std;

class CRectangle{
    private:
        int _iLength;
        int _iWidth;
    public:
        CRectangle(int length, int width);
        int area();
};

int CRectangle::area(){
    return _iLength * _iWidth;
}

CRectangle::CRectangle(int length, int width){
    _iLength = length;
    _iWidth = width;
}


int main(void){

 CRectangle rec(10, 20);

 cout << "The area of the rectangle is " << rec.area() << endl;

 return 0;
}

Remember, the main difference between data members in structures and data members in classes is that all data in a structure is public, whereas data members in classes are, by default, private.