Month: August 2016

Objects and Functions in C++

Let’s take a look at constructor overloading, objects as function arguments, and returning objects from functions.

CDistance.h

#ifndef CDISTANCE_H
#define CDISTANCE_H

class CDistance
{
    public:
        CDistance() : _meters(0), _centimeters(0.0) {}
        CDistance(int meters, double centimeters) : _meters(meters), _centimeters(centimeters) {}

        void getDist();
        void showDist();
        voidd addDist(CDistance a, CDistance b);

    private:
        int _meters;
        double _centimeters;
};

#endif // CDISTANCE_H

Our overloaded constructors use initialization lists to specify what we want to set the member variables to.

The scope resolution operator, ::, is used to specify what class something is associated with. We use the scope resolution operator when defining member functions outside the class declaration.

CDistance.cpp

#include "CDistance.h"
#include <iostream>

void CDistance::getDist() {
    std::cout << "Please enter meters: ";     
    std::cin >> _meters;
    std::cout << "Please enter centimeters: ";     
    std::cin >> _centimeters;
}

void CDistance::showDist(){
    std::cout << _meters << " m " << _centimeters << " cm "; 
} 

void CDistance::addDist(CDistance a, CDistance b){     
        _centimeters = a._centimeters + b._centimeters;     
        _meters = 0;    
     if(_centimeters >= 100){
        _centimeters -= 100;
        _meters++;
    }
    _meters += a._meters + b._meters;
}

The syntax for function parameters that are objects is the same as that for arguments are are simple times such as int or char.

A special example of passing in an object as an argument is the default copy constructor. The default copy constructor performs a member-wise copy of one object’s values to another.

#include "CDistance.h"

using namespace std;

int main()
{
    CDistance dOne;
    CDistance dTwo(5, 50);
    CDistance dThree;


    cout << "First Distance: " ;
    dOne.showDist();
    cout << endl;

    cout << "Second Distance: " ;
    dTwo.showDist();
    cout << endl;

    //default copy constructor
    dOne = dTwo;

    dThree.addDist(dOne, dTwo);

    dTwo.addDist(dOne, dThree);

    cout << "First Distance: " ;
    dOne.showDist();
    cout << endl;

    cout << "Second Distance: " ;
    dTwo.showDist();
    cout << endl;

    cout << "Third Distance: " ;
    dThree.showDist();
    cout << endl;


    return 0;
}

 

C++ Classes Review

Classes differ from structures in that they allow for data hiding, abstraction and encapsulation, inheritance,  and polymorphism. With a class definition, the class name is a type of name. A class is an abstract data type; a class specifies how objects of its type behave, are created and deleted, and are accessed.

The keywords private, protected, and public are used to specify three levels of access protection for data hiding and utility methods. private means that the member can only be accessed by the member functions and friends of the class. The private member is not directly accessible to the outside world. public means that member can be accessed by any function in the external environment. Public methods are interfaces to the outside world so that any other function can interact with it. protected means that the member can only be accessed by the class and member functions and classes derived from this class.

#include <iostream>

class CClock
{
    public:

        //constructors
        CClock();
        CClock(int h, int m, int s);

        //getters - setters
        void setHour(int h);
        void setMinute(int m);
        void setSecond(int s);

        int getHour() const;
        int getMinute() const;
        int getSecond() const;

        void printTime();

    private:

        int _hour;
        int _min;
        int _sec;
};

Member functions of a class are typically defined outside the class header file. The scope resolution operator, ::, is used to assign the function to a class.

The first member functions we can look at are the constructors. Constructors are special methods that are called automatically when an object of a class type is created. The constructor or constructors job is to initialize the object’s state – it’s member variables. If no constructor is specified then the compiler provides one by default.

Since C++ does not have zero initialization of member variables such as ints, it is a good idea to modify the default constructor so that it sets a default value for each member.

//default constructor
CClock::CClock()
{
    _min = 0;
    _hour = 0;
    _sec = 0;
}

//initialize the member variables to specific values
CClock::CClock(int h, int m, int s){
    _min = m;
    _sec = s;
    _hour = h;
}

Getters and setters are used to assign values to data members. Getters are usually declared to be const so as to ensure that the values aren’t accidentally modified during retrieval. Setters often do value checking to ensure that the new data is in the proper range.

//setters
void CClock::setHour(int h){
    //only set hour if it falls in the range 0 - 23
    if(0 <= h && h < 24){
        _hour = h;
    }
}

void CClock::setMinute(int m){
    if(0 <= m && m < 60){
        _min = m;
    }
}

void CClock::setSecond(int s){
    if(0 <= s && s < 60){
        _sec = s;
    }
}

//getters
int CClock::getHour() const {
    return _hour;
}

int CClock::getMinute() const {
    return _min;
}

int CClock::getSecond() const {
    return _sec;
}

Finally, we will set up a method to print the data in a formatted manner.

void CClock::printTime(){
    if(_hour < 10){
        cout << "0";
    }
    cout << _hour << ":";

    if(_min < 10){
        cout << "0";
    }
    cout << _min << ":";

    if(_sec < 10){
        cout << "0";
    }
    cout << _sec;
}

There are two ways to access a member of a class. We typically access a data or function member of the class object using ., the dot operator.When a pointer to an object of a class is used, we use the -> operator to access data or function members of the class.

#include "CClock.h"

using namespace std;

int main()
{
    CClock clockOne;
    CClock clockTwo(22, 15, 00);

    cout << "Clock One after default initialization: ";
    clockOne.printTime();
    cout << endl;

    cout << "Clock Two after being initialized to a specific time: ";
    clockTwo.printTime();
    cout << endl;

    clockOne.setHour(3);
    clockOne.setMinute(33);
    clockOne.setSecond(15);

    cout << endl;
    clockOne.printTime();

    return 0;
}

Function Templates

By adding template to the function definition, we can turn a function into a generic function. Absolute value is a good example of a generic function that can take multiple data types.

template <class T>
T absValue(T x){
    if(x < 0){
        return -x;
    }
    return x;
}


int main()
{
    int x = 2563;
    int y = -2914;
    int z = 47.5432;

    cout << "The absolute value of " << x << " is " << absValue(x) << endl;

    cout << "The absolute value of " << y << " is " << absValue(y) << endl;

    cout << "The absolute value of " << z << " is " << absValue(z) << endl;

    return 0;
}

Whenever we see T in a C++ program, chances are we are looking at a template. The use of T as a template parameter name is simply a convention.

When writing templates the problem is that we do not know what type or types T will actually be. So the function must be generic.

If a template takes multiple arguments, we should separate the arguments with a comma.

//returns a negative value if x is less than y
//0 if x and y are roughly the same
//a positive number if x is greater than y
template <class T, class U>
int compareValues(T x, U y){
    double rValue = x - y;
    double cValue = rValue;

    if(cValue < 0){
        cValue *= -1;
    }

    if(cValue < .000000001){
        return 0;
    }
    return rValue;
}

int main()
{
   int x = 47;
   double y = 19.99;
   char z = 's';

   if(compareValues(x, y) < 0){
    cout << x << " is greater than " << y << endl;
   } else {
    cout << y << " is greater than " << x << endl;
   }

   if(compareValues(y, z) < 0){
    cout << y << " is less than " << z << endl;
   } else {
    cout << y << " is greater than " << z << endl;
   }

    return 0;
}