Month: September 2014

Storage Classes, Scope and Linkage

The scope of variables is limited to the block of code they are declared in. Any variables declared inside the body of a function are not accessible outside the function, and cannot therefore be referred to by name; these are the function’s local variables.

#include <iostream>

using namespace std;

void funcAB(){
    cout << "funcAB() called." << endl;
    
    int a = 42;
    int b = 73;

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

int main(void){

    int c = 1138;

    cout << "c = " << c << endl;
    cout << "cannot refer to a or b in the main() function." << endl;

    funcAB();

}

As we seen, global identifiers are available to a function or block, as long as it is declared before the function or code block, and its identifier, i.e. its name, is different than any function or local variable identifiers.

The extern keyword can be employed to make the use of a global variable explicit; this enables a function to access a global variable that has been declared after the definition of a function.

#include <iostream>

using namespace std;


void funcSetDoubles();
void funcPrintDoubles();

void funcSetDoubles(){
    extern double dare;
    extern double trouble;
    dare = 2.41;
    trouble = 103.5075;
}

void funcPrintDoubles(){
    extern double dare;
    extern double trouble;

    cout << dare << endl;
    cout << trouble << endl;
}

double dare;
double trouble;


int main(void){

    dare = 390.315;
    trouble = 1.05;

    funcPrintDoubles();
    funcSetDoubles();
    funcPrintDoubles();

    return 0;
    
}



It is possible to declare a function away from its definition. A function declaration is just like the header of a function definition, although including the parameters’ names is optional. A function declaration introduces an identifier into the program.

The storage class of memory item is what type of storage is used for it. Automatic storage is on the program’s stack and is where function variables are allocated and stored. Static storage is where data is stored for the duration of the program’s lifetime. The heap is the section of memory where items allocated with new and new[] are stored.

Global variables are static variables, they are allocated and remain “in play” for the duration of the program. Variables declared within a block are automatic variables, they remain in scope only for the duration of the code block. We can create static variables inside a block by using the reserved keyword static.

#include <iostream>

using namespace std;

void funcTest(void);

int z = 0;  

int main(void){

    int y = 3000;
    extern int z;

    for(int i = 0; i < 10; i++){
        funcTest();
        y += i;
        z++;
        cout << "In main(): ";
        cout << "y = " << y << " z = " << z << endl;
    }
    return 0;

}

void funcTest(void){
    cout << "Inside funcTest(): ";

    static int x = 0;
    extern int z;

    int y = 3;
    z++;
    x = z + y;
    cout << "z = " << z << " y = " << y << " x = " << x << endl;
}

Remember, automatic storage allocates memory for the item at block entry and deallocates it at block exit. Static storage is allocated as long as the program executes.

A C++ program consists of a collection of files. A file, like a function, is a unit of scope, just as if it were enclosed in curly braces. Any variables declared in  file but outside of any function are global variables, they are in scope in any functions declared later in the file.

#include <iostream>

int x;
int y;

using namespace std;

void funcChangeX(int n){
    x += n;
}

void funcChangeY(int n){
    y -= n;
}

void funcShowXAndY(){
    cout << "x = " << x << " and y = " << y << endl;
}

int main(void){

    x = 1701;
    y = 404;

    cout << "x = " << x << endl;
    cout << "y = " << y << endl;

    funcChangeX(1999);

    funcChangeY(47);

    funcShowXAndY();    


    return 0;

}

To make sure that the necessary identifiers are in scope in all the files they are needed in, we must include the declarations in each file with the #include preprocessor statement. Library header files are included with angle brackets, and custom header files are included with quotation marks.

The linker takes the declarations to the appropriate definitions, and combines the compiled files of the program, along with the libraries it uses, into a single executable binary.

Access Specifiers in C++

The access specifiers private, protected, and public are used to set the access of a class’s members. We can make members private, visible only to code belonging to the same class, protected, visible to code only in the same class or classes derived from it, or else public, visible to all. By default, all members of a class are private.

#include <iostream>

using namespace std;


class CExmp{

    private:
        int _number;
    public:
        void incrementNumber();
        int getNumber();
        CExmp(int i);

};

CExmp::CExmp(int i){
    this->_number = i;
}

void CExmp::incrementNumber(){
    this->_number++;
}

int CExmp::getNumber(){
    return this->_number;
}


int main(void){


    CExmp objEmpOne = CExmp(47);
    
    objEmpOne.incrementNumber();

    cout << objEmpOne.getNumber() << endl;

    objEmpOne.incrementNumber();

    cout << objEmpOne.getNumber() << endl;

    return 0;

}

Note that as members are private by default, the private declaration isn’t, strictly speaking, necessary.

An important aspect of object oriented programming is data hiding. Data stored in an object should only be accessed via specific data access methods. In that way, we can control access to the data, ensuring that no illegal values are stored, and making sure the functionality of the object is predictable. We usually implement data access methods in pairs, as get and set methods, where the set method stores the data, and the get method retrieves the data.

#include <iostream>
#include <string>

using namespace std;

class CBikes{
    private:
        int _inStock;
        string _brand;
    public:
        void setInStock(int n);
        int getInStock();

        bool sellBikes(int n);
        
        string getBrand();
        
        CBikes(string s);
        

};

CBikes::CBikes(string s){
    this->_brand = s;
}

void CBikes::setInStock(int n){
    this->_inStock = n;
}

int CBikes::getInStock(){
    return this->_inStock;
}

bool CBikes::sellBikes(int n){
    if(this->_inStock - n >= 0){
        this->_inStock -= n;
        return true;
    } else {
        return false;
    }
}

string CBikes::getBrand(){
    return this->_brand;
}

int main(void){

    CBikes objSchwinn = CBikes("Schwinn");
    objSchwinn.setInStock(10);

    CBikes objGiant = CBikes("Giant");
    objGiant.setInStock(15);

    cout << "We have " << objSchwinn.getInStock() << " " << objSchwinn.getBrand() << "(s)" << endl;
    cout << "We have " << objGiant.getInStock() << " " << objGiant.getBrand() << " (s)" << endl;

    cout << "Selling 5 of the " << objSchwinn.getBrand() << "(s)" << endl;
    cout << "We now have " << objSchwinn.getInStock() << " of the " << objSchwinn.getBrand() << "(s)" << endl;

    cout << "Can we fill an order for 20 of the " << objGiant.getBrand() << "(s) ?" << endl;
    if(objGiant.sellBikes(20)){
        cout << "Yes! Sold. We now have " << objGiant.getInStock() << " left." << endl;
    } else {
        cout << "Nope. Not enough bikes." << endl;
    }

    return 0;

}

We use constructors to initialize data in an object as that object is being created. A constructor is a special method that is invoked automatically when the object is created. A constructor has the same name as the class itself, and not return value. When we declare objects, we can pass values to the constructor to initialize the state of the object.

#include <iostream>
#include <string>

using namespace std;

class CPet{
    private:
        string _name;
        string _type;
        int _age;
    public:
        string getName();
        void setName(string s);

        string getType();

        int getAge();
        void setAge(int n);

        CPet(string name, string type, int age);
};


string CPet::getName(){
    return this->_name;
}

void CPet::setName(string s){
    this->_name = s;
}

string CPet::getType(){
    return this->_type;
}

int CPet::getAge(){
    return this->_age;
}

void CPet::setAge(int n){
    this->_age = n;
}

CPet::CPet(string name, string type, int age){
    this->_name = name;
    this->_type = type;
    this->_age = age;
}


int main(void){

    CPet objDog = CPet("Fido", "dog", 5);
    CPet objBird = CPet("Polly", "bird", 3);

    cout << objDog.getName() << " is a " << objDog.getType() << " that is " << objDog.getAge() << " years old." << endl;
    cout << objBird.getName() << " is a " << objBird.getType() << endl;

    return 0;

}

If a constructor for the class is not provided, the compiler will provide one for us; this constructor is known as the default constructor.

Basic OOP and C++

Object oriented programming combines data and the operations on that data into units known as objects, that belong to classes, which define the objects.

A class is a combination of a data structure and its related algorithms. The data structure aspect of a class differs from a traditional struct in that it is encapsulated – its fields, known as member variables, can have their access restricted so that they can only be manipulated through the class’s related algorithms, known as member functions. An object, better called a class instance in my opinion, is a particular set of values stored in the data members and accessed through its object identifier.

To define a class  we use the class reserved word, followed by a set of parentheses, followed by a pair of curly braces, and ending with a semicolon.

Within the class definition, we can place member variables and member functions. The member variables are declared as variables are declared everywhere. The member functions are declared by giving their function prototype.

#include <iostream>

class CTest{
    int a;
    double b;

    void DoSomething();

};

int main(void){

    CTest objA;

    CTest objB;

    return 0;

}

Of course, we can’t do much with the class objects we just declared and instantiated. Why? By default, all members of a class are private. When a class member is private, we can’t access  it outside of the class; this includes main(). The members of a class can be either private or protected, or a third category in between the two. To mark all of the public methods, we should use the access specifier public followed by a semicolon.

Once we have instantiated an object, we can access the members of the class with the dot operator, placed after the object’s identifier, and followed by the member name. We can, however, only access the public members of the class.

While we place a function prototype in the class definition, to define the member function itself we must place the class name followed by the scope resolution operator, two consecutive semicolons, followed by the member function’s name and list of parameters.

#include <iostream>

class CPoint{
    public:
        int x;
        int y;
        void print();
};

using namespace std;

int main(void){
    CPoint objA;

    objA.x = 11;
    objA.y = -18;

    objA.print();

    return 0;
    
}

//member function 
//note the scope resolution operator
void CPoint::print(){
    cout << "(" << x << ", " << y << ")" << endl;
}

Typically, we want to prevent the outside world from being able to manipulate a class’s instance variables. Instead of allowing direct access to the data, we want to impose an intermediary in the form of the class’s member functions, which define how the data may be set, altered, and accessed. Usually, every class has member functions for returning the values stored in member variables, and also has member functions for modifying the values stored in member variables.

#include <iostream>

class CProposition{
    bool p;
    bool q;

    public:
        void setP(bool value);
        bool getP();
        void setQ(bool value);
        bool getQ();

        void printConjunction();
        void printDisjunction();

};

using namespace std;

int main(void){

    CProposition objPropA;
    objPropA.setP(true);
    objPropA.setQ(true);
    cout << "p is " << objPropA.getP() << endl;
    cout << "q is " << objPropA.getQ() << endl;

    objPropA.printConjunction();
    objPropA.printDisjunction();

    objPropA.setP(false);

    objPropA.printConjunction();
    objPropA.printDisjunction();

    return 0;

}


void CProposition::setP(bool value){
    p = value;
}

bool CProposition::getP(){
    return p;
}

void CProposition::setQ(bool value){
    q = value;
}

bool CProposition::getQ(){
    return q;
}

void CProposition::printConjunction(){
    cout << "p ^ q = ";
    if(!(p && q)){
        cout << " false. ";
        if(p==q){
            cout << " Both are false.";
        } else if(!p){
            cout << " p is false; q is true.";
        } else {
            cout << " q is false, p is true.";
        }
    } else {
        cout << " true. ";
    }
    cout << endl;
}

void CProposition::printDisjunction(){
    cout << "p v q = ";
    if(p || q){
        cout << " true. ";
        if(p == q){
            cout << "Both are true.";
        } else if(!p){
            cout << "q is true; p is false;";
        } else {
            cout << "p is true; q is false;";
        }
    } else {
        cout << " false.";
    }
    cout << endl;
}

Functions that only access private member variables are called accessors; as an added precaution, we can add the keyword const at the end of the function headers to ensure that the value cannot be modified.

We can use constructors to guarantee that a class instantiation’s member variables are initialized. A constructor is a function called whenever an object is instantiated. The name of the constructor is the same name as the name of the class. Unlike other functions, the constructor has no type. One class can have multiple constructors, as long as they have different parameter signatures.

#include <iostream>

class CCircle{
    private:
        double _radius;
        static const double pi = 3.14159;
    public:
        void setRadius(double r);
        double getRadius() const;
        double area() const;
        double circumference() const;
        CCircle(double radius = 0);
};

using namespace std;

int main(void){

    CCircle circle1;
    CCircle circle2(42.40);

    cout << "radius of circle1 = " << circle1.getRadius() << endl;
    cout << "radius of circle2 = " << circle2.getRadius() << endl;
    cout << "area of circle2 = " << circle2.area() << endl;
    circle1.setRadius(5.2);
    cout << "radius of circle1 = " << circle1.getRadius() << endl;
    cout << "circumference of circle1 = " << circle1.circumference() << endl;

    return 0;

}


CCircle::CCircle(double radius){
    //this unnecessary 
    //but habit of mine
    this->_radius = radius;
}

void CCircle::setRadius(double r){
    //let's screen the data
    if(r > 0){
        _radius = r;
    } else {
        _radius = 0;
    }
}

double CCircle::getRadius() const{
    return _radius;
}

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

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

As we have seen above, a constructor, like other functions, can have default parameters. We also saw above a new type of member variable, a static member variable. A class can have static member variables as well as static member functions; in both cases, they are declared with the keyword static. Static member functions and variables are accessed using the class name and the scope resolution operator. Neither static member variables nor static member functions need a class instantiation in order to be used.

The File I/O Classes in C++

The ifstream class derives from the istream class, and enables users to access files and read data from them. The ofstream class derives from the ostream class, and enables users to access files and write data to them. The fstream class is derived from both the ifstream and ofstream classes, and enables users to access files for both data input and output. These functions are defined in the fstream header file.

Declaring input and ouput objects is simple.

#include <fstream>

using namespace std;

int main(void){

    //input stream object
    ifstream infile;

    //output stream object
    ofstream outfile;

    return 0;

}

The open() function is a member of the ifstream or ofstream class; the function in its most basic form takes a single argument, the path to the desired file. We can check the ifstream or ofstream object directly as a binary value to test whether or not the file is open and the stream is read for I/O.

As second argument that can be sent to the open() member function is the mode, which is based on a set of predefined constants. The ios::in constant opens the file for reading, and the ios::out constant opens the file for writing.

#include <iostream>
#include <fstream>

using namespace std;

int main(void){

    cout << "ios::in " << ios::in << endl;
    cout << "ios::out " << ios::out << endl;
    cout << "ios::app " << ios::app << endl;
    cout << "ios::ate " << ios::ate << endl;
    cout << "ios::trunc " << ios::trunc << endl;
    cout << "ios::binary " << ios::binary << endl;    
    

    return 0;

}

Note that the definition of the open() function uses default values.

The << and >> operators are overloaded, which means we can use them for file I/O as well as with stdin and stdout.

#include <iostream>
#include <fstream>

using namespace std;

int main(void){

    char ch;

    ifstream source;
    ofstream target;

    source.open("test.txt");

    target.open("test_copy.txt");

    if(source){
        if(target){
            while(source.get(ch)){
                target.put(ch);
            }
            source.close();
            target.close();
        }    
    }

    return 0;

}

We can use the seekg(), seekp(), tellg() and tellp() functions to enable random access of files. These functions change the position of an I/O stream pointer. The seekg() and tellg() functions are used with ifstream objects, and the seekp() and tellp() functions are used with ofstream objects.

#include <iostream>
#include <fstream>

using namespace std;

int main(void){

    ifstream infile;
    ofstream outfile;

    int i = 0;
    char ch;

    infile.open("test.txt");
    outfile.open("test_partial.txt");

    if(infile && outfile){
        infile.seekg(15);
        while(infile.get(ch)){
            outfile.put(ch);
        }
    
        infile.close();
        outfile.close();
    }

    return 0;

}

A Tour of cout

cout is an ostream object, and its << operator is overloaded for all of the basic types, as well as c-style strings that use char pointers

#include <iostream>

using namespace std;

int main(void){

    double d = 0.57721;
        char *szString = "If wishes were fishes..";

    cout << d << endl;
    cout << szString << endl;    

    return 0;

}

The << operator returns a reference to the cout object itself, thus allowing us to chain insert operations.

The cout member function put() displays characters, and the write() function displays strings.We can pass the put() function character literals as well as integer and floating point values; the numeric values are converted into their corresponding ASCII characters. The write() function is designed to work with C-style char arrays.

#include <iostream>
#include <string>

using namespace std;

int main(void){

    char *szStr ="You have failed us, Torgo. For this, you must die!";
    
    cout.put('A');

    cout.put('B').put('C');

    cout << endl;

    cout.write(szStr, sizeof(szStr));
    
    cout << endl;

    cout.write(szStr, 18) << endl;

    return 0;

}

By default, cout displays char values as one character wide, int values are displayed as base 10 numbers in fields sized to the number of positions in the number, strings are likewise displayed in fields of the same length as the number of characters in the string, and floating point numbers are by default displayed in fields of six digits, with trailing zeros cut off, and the decimal portion truncated as needed.

We can use the cout member function width() to specify how wide we want output fields to be. We can also use the manipulators right and left to make the output right or left justified.

#include <iostream>

using namespace std;


int main(void){

    cout.width(25);
    cout << "El Psy Congroo";

    cout.width(15);
    cout << 2600 << endl;

    cout << left;

    cout.width(35);
    cout << "You're killing me, Smalls!";
    cout.width(10);
    cout << 7800;
    cout << 1999 << endl;

    return 0;
}

We can use the setf() function to configure formatting for the cout object. We pass the setf() function arguments made up of ios_base class constants such as ios_base::boolalpha to display bool values as true or false instead of 1 or 0, and ios_base::showpoint to show a trailing decimal point.

#include <iostream>

using namespace std;

int main(void){

    cout << true << " " << false << endl;

    cout.setf(ios_base::boolalpha);

    cout << true << " " << false << endl;

    cout << 192.168 << " ";

    cout.setf(ios_base::scientific, ios_base::floatfield);

    cout << 192.168 << endl;

    cout.width(30);
    
    cout << "Saluton, Mundo!" << endl;

    cout.setf(ios_base::left, ios_base::adjustfield);

    cout.width(30);

    cout << "Saluton, Mundo!" << endl;

    return 0;

}

To set numeric precision, we can use the setprecision manipulator. To use the setprecision manipulator, we must include the iomanip header.

#include <iostream>
#include <iomanip>

using namespace std;

int main(void){

    double de = 2.7182818284;


    cout << "e = " << de << endl;

    cout << setprecision(5);

    cout << "e = " << de << endl;

    cout << setprecision(9);

    cout << "e = " << de << endl;

    return 0;

}

We can overload the << operator, and in doing so we can specify how we want our custom classes to work with the ostream class. To do so, we must make the << operator function a friend of our custom class so that this function has access to the private data within our class.

#include <iostream>
#include <string>

using namespace std;

class CWorker{
    private:
        int pid;
        string firstName;
        string lastName;
        int age;
    public:
        CWorker(int pid, string firstName, string lastName, int age);
        friend ostream &operator<<(ostream &stream, const CWorker & w);
};

int main(void){

    CWorker samsa(500, "Gregor", "Samsa", 30);

    cout << samsa;

    return 0;
}

CWorker::CWorker(int pid, string firstName, string lastName, int age){
    this->pid = pid;
    this->firstName = firstName;
    this->lastName = lastName;
    this->age = age;
}

ostream &operator<<(ostream &stream, const CWorker & w){
    cout << "ID#:" << w.pid << endl;
    cout << "Name: " << w.lastName << ", " << w.firstName << endl;
    cout << "Age: " << w.age << endl;
    return stream;
}

More on Classes in C++

We can use constructors to guarantee that the data members of a class are initialized. There are two types of constructors: with parameters and without parameters. The default constructor does not take any parameters. The name of the constructor is the same as the name of the class.  A constructor, unlike other functions, does not have a type. Constructors are executed automatically when a class instantiation enters scope.

#include <iostream>

class classA{
    public:
        classA();
};

class classB{
    public:
        classB(int a);
};

using namespace std;

int main(void){

    classA objA;
    classB objB(1138);

    return 0;
}

classA::classA(){
    cout << "object of type classA instantiated." << endl; 
}

classB::classB(int a){
    cout << "classB object instantiated. Received parameter " << a << "." << endl;
}

A class can have multiple constructors, but all constructors have the same name, the name of the class. If a class has multiple constructors, each constructor must have a different set of parameters.  Which constructor executes depends on the arguments passed to the class object when the class object is declared.

#include <iostream>

class CExmpOne{
    public:

        CExmpOne();
        CExmpOne(int iX);
        CExmpOne(double dY);
};


using namespace std;

int main(void){

    CExmpOne objA(1919);
    CExmpOne objB;
    CExmpOne objC(23.14);

    return 0;
}

CExmpOne::CExmpOne(){
    cout << "CExmpOne() called." << endl;
    cout << "Object instantiated." << endl << endl;
}

CExmpOne::CExmpOne(int iX){
    cout << "CExmpOne(int) called." << endl;
    cout << "Object instantiated." << endl << endl;
}

CExmpOne::CExmpOne(double dY){
    cout << "CExmpOne(double) called." << endl;
    cout << "Object instantiated." << endl << endl;
}

Remember, when a class object is declared, a constructor is automatically called. To call the default constructor, we omit parentheses after the object name in the object declaration statement.

The constructor’s parameters are usually assigned to member variables.

#include <iostream>
#include <cmath>

class testClass{
    private:
        int iX;
        int iY;
        double dY;
    public:
        void print();

        testClass();
        testClass(int x);
        testClass(int x, int y);
        testClass(int x, double y);
};

using namespace std;

int main(void){

    testClass objTOne;
    testClass objTTwo(1999, .001);
    testClass objTThree(1138);
    testClass objTFour(88, 118);

    objTThree.print();
    objTTwo.print();
    
    return 0;

}


testClass::testClass(){
    iX = 0;
    iY = 0;
    dY = 0.0;
}

testClass::testClass(int x){
    iX = x;
    iY = 0;
    dY = 0.0;
}

testClass::testClass(int x, int y){
    iX = x;
    iY = y;
    dY  = 0.0;
}

testClass::testClass(int x, double y){
    iX = x;
    iY = 0;
    dY = y;
}

void testClass::print(){
    cout << iX;
    if(iY!=0){
        cout << " + " << iY << " = " << iX + iY;
    }
    if(abs(dY)>0.00000001){
        cout << " + " << dY << " = " << iX + dY;
    }
    cout << endl;
}

A constructor can also have default parameters, thereby reducing the need to declare multiple constructors. We can then expand the definition default constructor to include not only constructors with no parameters, but also constructors with all default parameters.

#include <iostream>

class CClock{
    private:
        int hours;
        int minutes;
        int seconds;
    public:
        CClock(int hours = 0, int minutes = 0, int seconds = 0);
        void printTime();
        void incrementSeconds();
        void incrementMinutes();
        void incrementHours();
};

using namespace std;

int main(void){

    CClock objClockA;
    CClock objClockB(10, 30);
    CClock objClockC(23, 59, 59);

    objClockA.printTime();
    objClockB.printTime();
    objClockC.printTime();

    objClockA.incrementHours();
    objClockA.printTime();

    objClockC.incrementSeconds();
    objClockC.printTime();

    return 0;

}

CClock::CClock(int hours, int minutes, int seconds){
    if(hours > 0 && hours < 24){
        this->hours = hours;
    } else {
        this->hours = 0;
    }

    if(minutes > 0 && minutes < 60){
        this->minutes = minutes;
    } else {
        this->minutes = 0;
    }

    if(seconds > 0 && seconds < 60){
        this->seconds = seconds;
    } else {
        this->seconds = 0;
    }
}

void CClock::printTime(){
    cout << hours << ":" << minutes << ":" << seconds << endl;
}

void CClock::incrementHours(){
    if(hours!=23){
        hours++;
    } else{
        hours = 0;
    }
}

void CClock::incrementMinutes(){
    if(minutes!=59){
        minutes++;
    } else {
        CClock::incrementHours();
        minutes = 0;
    }
}

void CClock::incrementSeconds(){
    if(seconds!=59){
        seconds++;
    } else{
        CClock::incrementMinutes();
        seconds = 0;
    }
}

Constructors should be used to provide guaranteed initialization of member variables. While a default constructor will be provided if none is specified, C++ does not automatically initialize variables, and that includes member variables.

When we declare an array of objects, the default constructor is called for each object.

#include <iostream>

class CExample{
    private:
        int iVar;
        double dVar;
    public:
        CExample(int iVar = 0, double dVar = 0);
        void setiVar(int i);
        void setdVar(double d);
        void print();
};


using namespace std;

int main(void){

    CExample CarrExmp[10];

    CarrExmp[3].setiVar(47);
    CarrExmp[3].setdVar(802.3);
    CarrExmp[3].print();

    return 0;

}


CExample::CExample(int iVar, double dVar){
    this->iVar = iVar;
    this->dVar = dVar;
    cout << "default constructor called." << endl;
}

void CExample::setiVar(int i){
    iVar = i;
}

void CExample::setdVar(double d){
    dVar = d;
}

void CExample::print(){
    cout << iVar << ", " << dVar << endl;
}

Function Templates in C++

Function templates empower us to create multiple functions in which the code is the same, but the data handled is of different types. A function template simplifies the process of overloading functions by keeping us from having to repeat the same code over and over for different parameters.

A function template is defined using the keyword template. We use a placeholder, typically the letter T, for the type of data we want the function to operate on.

#include <iostream>

template <class Type>
Type larger(Type x, Type y);

using namespace std;

int main(void){

    int iValue = 8088;
    int iValue2 = 404;

    double dValue = 62.324;
    double dValue2 = 917.7;

    cout << "The larger of " << iValue;
    cout << " and " << iValue2 << " is ";
    cout << larger(iValue, iValue2) << endl;

    cout << "The larger of " << dValue;
    cout << " and " << dValue2 << " is ";
    cout << larger(dValue, dValue2) << endl;

    return 0;
}

template <class Type>
Type larger(Type x, Type y){
    if(x >= y){
        return x;
    } else {
        return y;
    }
}

Note that the angle brackets are necessary.

Programmers typically use a capital T to denote the placeholder, which we will now do as well. This is the same style used in declaring generic methods in C# and Java, with virtually the same syntax as well. Both of those languages “grew” out of C++, which is one of the reasons I think C++ and C are so relevant, at least in terms of learning how to code. C# makes a lot more sense in the light of C++ than it does on its own, I think.

When we use a code template, the C++ compiler will instantiate the correct version of the function, depending on the arguments passed to it.

#include <iostream>

template <class T>
T square(T data);

template <class T>
void printSquare(T data);

using namespace std;

int main(void){

    int iValue = 16;

    cout << iValue << " squared is " << square(iValue) << endl;

    printSquare(14.571);

    printSquare(42);
    

    return 0;

}

template <class T>
T square(T data){
    return data * data;
}

template <class T>
void printSquare(T data){
    cout << data << "^2 = " << square(data) << endl;
}

As we have seen, a function template defines a function in terms of an arbitrary type for which a specific type can be substituted. Since types are represented by parameters, we sometimes refer to this template feature as parameterized types. The template is not a function itself, rather it is a blueprint that enables the compiler to create functions.

Of course, it’s possible to specify a template that takes more than one type of data. In the following example, we will define a function called Add() that will take data of two different types, and return a value of the type of the first parameter.

#include <iostream>

template <class ReturnType, class OtherType>
ReturnType Add(ReturnType x, OtherType y);

using namespace std;

int main(void){

    int iX = 14;
    double dY = 17.99;

    cout << iX << " + " << dY << " = ";
           cout << Add(iX, dY) << endl;

    cout << dY << " + " << iX << " = ";
    cout << Add(dY, iX) << endl;    


    return 0;
}


template <class ReturnType, class OtherType>
ReturnType Add(ReturnType x, OtherType y){
    return x + (ReturnType)y;
}

We can overload templates in the same way that we overload regular function definitions. Just as with regular overloading, template overloading requires distinct function signatures in order to work.

#include <iostream>

template <class TOne, class TTwo>
void CopyArray(TOne arrParamOne[], TTwo arrParamTwo, int bounds);

template <class T>
void CopyArray(T arrParamOne[], T arrParamTwo, int bounds);

template <class T>
void PrintArray(T arrParam, int bounds);

using namespace std;

int main(void){

    double dArray[] = {2.718, 0.57721, 3.14159, 1.61803, 15.3465111};
    double dArrayTwo[5];

    int iArray[] = {73, 2600, 404, 6174, 8086};

    PrintArray(iArray, 5);
    
    CopyArray(dArrayTwo, dArray, 5);
    
    PrintArray(dArrayTwo, 5);
    
    CopyArray(iArray, dArrayTwo, 5);

    PrintArray(iArray, 5);
    
    return 0;
}


template <class TOne, class TTwo>
void CopyArray(TOne arrParamOne[], TTwo arrParamTwo, int bounds){
    for(int i = 0 ; i < bounds; i++){
        arrParamOne[i] = (TOne)arrParamTwo[i];
    }
}


template <class T>
void CopyArray(T arrParamOne[], T arrParamTwo, int bounds){
    for(int i = 0; i < bounds; i++){
        arrParamOne[i] = arrParamTwo[i];
    }
}


template <class T>
void PrintArray(T arrParam, int bounds){
    for(int i = 0; i < bounds; i++){
        cout << arrParam[i] << " ";
    }
    cout << endl;
}

We use templates when we need functions that use the same basic algorithm with a variety of types.

 

 

 

Classes vs Stacks in C++

The class and the stack are similar in some aspects.

It is easy to implement a data structure in C++. If we want to create an object that has no member functions, just data, a struct is more than sufficient. A class that has no members other than the default constructor and destructor would be similar in layout and “feel” to a struct.

#include <iostream>

using namespace std;

int main(void){

    struct SData{
        int iValue;
        double dValue;
        string strValue;
    };

    class CData{
        int iValue;
        double dValue;
        string strValue;
    };

    return 0;

}

The key difference then between a struct and a class without any member functions is data hiding – a class’s member variables are by default set to private.  This hides the value from functions outside the class – a big plus plus.

As an example, let’s compare an implementation of a stack using structs with an implementation using classes.

A stack is a data structure that accepts data using a push operation, and removes data using a pop operation. Data is stored in a last in, first out order, abbreviated LIFO. It’s similar to a stack of plates, or, unfortunately, the emails in my inbox.

Suppose we have a stack that stores numbers. The stack starts out empty, and we push 9, 14, and 27 onto the stack using three push operations. When we execute a pop operation, the number we get is 27, the last number pushed onto the stack.

First, let’s design a simple stack using an array to store the data and a structure to store the array. We will then need a function to push an item onto the stack, a function to pop an item off of the stack, and a function to initialize the stack.

#include <iostream>

using namespace std;

const int Stack_Size = 100;

struct stack{
    int iCount;
    int iaData[Stack_Size];
};


int stackPop(struct stack &theStack);
void stackPush(struct stack &theStack, int iValue);
void stackInit(struct stack &theStack);

int main(void){

    struct stack exmpStack;

    stackInit(exmpStack);

    //push some values on
    stackPush(exmpStack, 533);
    stackPush(exmpStack, 97);
    stackPush(exmpStack, 66);
    stackPush(exmpStack, 62);

    cout << "Item on top of the stack is " << stackPop(exmpStack) << endl;
    cout << "Next item is " << stackPop(exmpStack) << endl;    


    return 0;
}

//remove an item and return it to
//the calling function
int stackPop(struct stack &theStack){
    //one item less in the stack
    theStack.iCount--;
    //we can use that number
    //since arrays are indexed starting at 0
    return theStack.iaData[theStack.iCount];
} //end stackPush()

//add an item
void stackPush(struct stack &theStack, int iValue){
    theStack.iaData[theStack.iCount] = iValue;
    theStack.iCount++;
} //end stackPop()

//initilize the structure
void stackInit(struct stack &theStack){
    theStack.iCount = 0;
}

The problem is that the stack and its related functions are defined separately, forcing us to pass the struct variable into each method. The structure’s fields are also available to anyone. We could easily corrupt the stack.

All right, now let’s see how the class implementation goes.

A class definition begins with the keyword class. We will declare two class variables, and set them to private by using the keyword private followed by a semicolon to indicate that the variables that follow are private. The keyword private defines the variables as being inaccessible to non-member functions. We will make set the class’s member functions to public using the keyword public followed by as semicolon.

All functions that are members of the class must be defined with the class name followed by two semicolons in front of the function name. The two semicolons are what is known as a scope operator.

#include <iostream>

using namespace std;

const int Stack_Size = 100;

class CStack{
    //private class variables
    //only accessible through the
    //class functions
    private:
        int iCount;
        int iData[Stack_Size];
    //class functions are declared public
    //only way to access the values stored
    //on the stack
    public:
        void init(void);
        void push(const int iParam);
        int pop();

};


int main(void){

    CStack theStack;
    theStack.init();

    theStack.push(47);
    theStack.push(711);
    theStack.push(73);


    cout << theStack.pop() << endl;
    cout << theStack.pop() << endl;
    cout << theStack.pop() << endl;

    return 0;
}


void CStack::init(){
    iCount=0;
}

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

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

As we can see, using a class is much like using a structure. Declaring the class variable is the same, except of course we use the keyword class instead of the keyword struct. Accessing the class members is the same as well; it’s done using the dot operator. The difference is that we can only access the class members that are set to public, and the class members may be either functions or variables.

The one annoyance with the stack class we have defined is that we have to explicitly initialize it. It would be better if we just used a constructor, which is automatically called when an instance of the class is created. The constructor function has the same name as the class. Like other functions, the class constructor can accept arguments.

#include <iostream>

using namespace std;

class CPerson{
    private:
        string strName;
        int iAge;
    public:
        CPerson(string strNameParam, int iAgeParam);
        void PrintData();

};

int main(void){

    class CPerson joe("Jospeh Johnson", 32);
    joe.PrintData();

    return 0;
}

CPerson::CPerson(string strNameParam, int iAgeParam){
    strName = strNameParam;
    iAge = iAgeParam;
}

void CPerson::PrintData(){
    cout << "Name: " << strName << endl;
    cout << "Age: " << iAge << endl;
}

Note well that the class constructor is automatically called when the variable is created.

 

Functions in C++

A function definition is a function header followed by a statement or statements contained within curly braces. The function header declares the return type, the name of the function, and the parameter list. A function may have zero to multiple parameters.

A void function doesn’t return a value. A void function is declared by giving the return type of void.

A function is called by using its name in a statement.

#include <iostream>

using namespace std;

void printDoubleLine(){
    cout << endl << endl;
}

void printIntArgumentTwice(int iparamN){
    cout << iparamN << endl;
    cout << iparamN << endl;
}


int main(void){

    int i = 47;

    cout << "calling function printIntArgumentTwice()" << endl;

    printIntArgumentTwice(i);

    cout << "calling function printDoubleLine()" << endl;

    cout << "calling function printIntArgumentTwice() again" << endl;

    printIntArgumentTwice(4004);

    return 0;
}

Note that even when a function takes no arguments we still need to include the parentheses in the function header and when calling the function.

All C and C++ programs have at least one function, the main() function. This function accepts no arguments in our examples (although it can be specified to accept command line arguments) and returns an int value.

Functions that return a value must include a return statement. The return statement must return a value of the type specified in the function definition.

#include <iostream>

using namespace std;

string returnQuote(){
    string strQuote = "Human sacrifice, dogs and cats living together... mass hysteria!";
    return strQuote;
}

double returnDouble(){
    return 0.57721;
}


int main(void){

    string strOne = "I solemnly swear that I am up to no good.";
    string strTwo = returnQuote();
    
    cout << strOne << endl;
    cout << strTwo << endl;
    cout << returnDouble() << endl;

    return 0;
}

C++ supports passing arguments by value and by reference. By default, parameters are a copy of the values passed in as arguments. We can specify call by reference by placing an ampersand before the parameter’s name. When passing a value be reference, any modification made to the value will continue beyond the lifetime of the function, i.e. be permanent.

#include <iostream>

using namespace std;

void funcSwitchIntValues(int &i, int &j){
    int iTemp = i;
    i = j;
    j = iTemp;
}

int main(void){

    int iValueOne, iValueTwo;

    iValueOne = 1138;
    iValueTwo = 8088;

    cout << "iValueOne = " << iValueOne << endl;
    cout << "iValueTwo = " << iValueTwo << endl;
    cout << "calling funcSwitchIntValues()" << endl;

    funcSwitchIntValues(iValueOne, iValueTwo);

    cout << "iValueOne = " << iValueOne << endl;
    cout << "iValueTwo = " << iValueTwo << endl;


    return 0;

}

Having functions that accept parameters by reference enables the function to return multiple values. Whether or not that is a good thing is up to the programmer and the situation the function is being used in. Generally speaking, passing by reference does often help to optimize a program and conserve system memory.

Adding the qualifier const in front of a parameter that has accepted an argument by reference prevents the variable’s contents from being altered in the function, essentially the same as passing a pointer to a constant value, as in const int * constiPtr.

#include <iostream>

using namespace std;

struct SPerson{
    string firstName;
    string lastName;
    int age;
};


void funcInitializeSPerson(struct SPerson &Sparam){
    Sparam.firstName = "John";
    Sparam.lastName = "Doe";
    Sparam.age = 32;
}

void funcPrintSPerson(const struct SPerson &Sparam){
    cout << "First Name: " << Sparam.firstName << endl;
    cout << "Last Name: " << Sparam.lastName << endl;
    cout << "Age: " << Sparam.age << endl;
}

int main(void){

    struct SPerson Sx;

    funcInitializeSPerson(Sx);
    funcPrintSPerson(Sx);

    return 0;
}

For our next example, we will write a small program to count vowels. In the program, we will have one function call another function. As a general design principle, it’s best to have one function perform one task, even though the additional function calls might impose some extra overhead, it makes it easier to reuse code and debug problems.

#include <iostream>

using namespace std;

bool funcIsVowel(const char &c){
    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}

void funcConvertToLower(string &s){
    int i = 0;
    while(s[i]){
        s[i] = tolower(s[i]);
        i++;
    }
}

int funcCountVowels(string s){
    funcConvertToLower(s);
    int i = 0;
    int iReturnValue = 0;
    while(s[i]){
        if(funcIsVowel(s[i])){
            iReturnValue++;
        }
        i++;
    }

    return iReturnValue;
}

int main(void){
    
    string s = "The President has been kidnapped by ninjas. Are you a bad enough dude to rescue the President?";

    cout << "string " << s << " has " << funcCountVowels(s) << " vowels." << endl;

    return 0;

}

 

 

 

 

 

 

Introduction to Classes in C++

A class is a derived type. Like a structure, a class may have different types. Furthermore, a class may have functions as well, including operators.

An object is, in this context, an instantiation of a class; it is a class that has state. We can think of an object as a self-contained entity that stores its own data and references a set of functions that it can call via itself.

A class declaration begins with the keyword class and ends with a semicolon.

#include <iostream>

class Cfoo{

};

class Cbar{

};

int main(void){

    Cfoo foo;
           Cbar bar;

    return 0;
}

To reiterate, a class definition is contained within curly braces following the class name, and there must be a semicolon placed after the closing curly brace.

A class combines data structures and algorithms, essentially. In a sense, it’s a self-contained program that we can use like blocks to build bigger, interdependent programs.

We can declare objects, or instances, of a class by using the class name followed by the name we wish to give the object.

#include <iostream>

using namespace std;

class Person{
    public:
    string firstName;
    string lastName;
    int age;
};


int main(void){

    Person hachimaki;
    hachimaki.firstName = "Hachirota";
    hachimaki.lastName = "Hoshino";
    hachimaki.age = 25 << endl;

    cout << "First Name: " << hachimaki.firstName << endl;
    cout << "Last Name: " << hachimaki.lastName << endl;
    cout << "Age: " << hachimaki.age;

    return 0;
}

An object’s member data can be accessed by using the object’s identifier followed by a period followed by the member variable’s identifier.

By default, all class members are set to private. We can declare member variables and member functions to be public by using the public keyword. Public class members are accessible from outside the class, whereas private class members are only accessible within the class. It may seem strange to want to “hide” parts of the class from the outside world, but it’s actually an important part of encapsulation, which aims to make classes as reusable and easy to maintain as possible.

Let’s create a class to store and manipulate rational numbers.

#include <iostream>

using namespace std;

class CRationalNum{
    public:
        void Assign(int i, int j);
        double Convert();
        void Print();
    private:
           int _inum, _iden;
};

int main(void){

    CRationalNum objRNum;

    objRNum.Assign(42, 47);

    objRNum.Print();

    cout << " (" << objRNum.Convert() << ")" << endl;


    return 0;

}


//------------class methods------------------------
void CRationalNum::Assign(int i, int j){
    _inum = i;
    _iden = j;
}

double CRationalNum::Convert(){
    return (double)_inum/_iden;
}

void CRationalNum::Print(){
    cout << _inum << "/" << _iden;
}

The member variables are declared to be private, and are preceded by an underscore, which is a somewhat common style convention.

Note when actually defining the class’s methods we need to use the class name followed by the scope resolution operator so that the compiler knows that the functions are members of class CRationalNum.