// Demo program that demonstrates class constructors
// and a friend declaration.

#include <iostream>

// NOTES:

// (1)
// IntStack class has a friend function. It means that print_stack()
// has unlimited access to all private member variables and functions
// of IntStack class. Why not make print_stack() a member function of
// IntStack? Because we may need this function for debugging purposes
// only and not pollute the public interface of IntStack class.

// (2)
// IntStack here has two constructors. One of them is a default constructor.
// Strangely, the default constructor is private. This is legal way to
// disable creation of the IntStack objects without providing parameters.
// We might say that IntStack class is no longer "default constructible."
// This feature is rather rare case, because more often than not default
// constructors are very convinient and increase the chance of the class
// to be reused in the future projects.

// (3)
// Please take the implementation of the member functions of IntStack
// class with the grain of salt. The implementation is intentionally
// hardwired to only three elements of the "storage" array. It does
// demonstrate that the object actually modifies its member variables,
// although in a shockingly primitive way.

class IntStack
{
    friend void print_stack( IntStack* pstack );
    static const int STACK_SIZE = 3; 
    int storage[ STACK_SIZE ];
public:
    // constructors
    IntStack( int el1, int el2, int el3 );
private:
    IntStack();
};

// IntStack.cpp
IntStack::IntStack()
{
    storage[ 0 ] = 0;
    storage[ 1 ] = 0;
    storage[ 2 ] = 0;
}

IntStack::IntStack( int el1, int el2, int el3 )
{
    storage[ 0 ] = el1;
    storage[ 1 ] = el2;
    storage[ 2 ] = el3;
}

void print_stack( IntStack* pstack )
{
    // This function has no problem accessing private data of
    // the class where it was declared a "friend".
    // Thus, friendship breaks the rules of encapsulation
    // and is typically used inside class libraries to
    // do things unknown to a normal user of that library.
    std::cout << pstack->storage[ 0 ] << ' ';
    std::cout << pstack->storage[ 1 ] << ' ';
    std::cout << pstack->storage[ 2 ] << ' ';
}

int main()
{
    IntStack stack; // will not compile because default constructor is private.
    IntStack stack2( 111, 222, 333 );
    IntStack many_stacks[ 5000 ];
    print_stack( &stack );
    print_stack( &stack2 );
    return 0;
}

