Link to a good C++ reference

https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp6_Inheritance.html

Advertisements

Function returns a reference

I wonder what happen when a function returns a reference. Let’s consider the following script:

// Example program
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int & foo (int & x){
    x++;
    return x;
}
int foo2 (int & x){
    x++;
    return x;
}
int main()
{
    int var1(4), var2(5);
    cout << "var1 = " << var1 << " var2 = " << var2 << endl;
    foo(var1); foo2(var2);
    cout << "var1 = " << var1 << " var2 = " << var2 << endl;
    foo(var1) = 8;
    cout << "var1 = " << var1 << " var2 = " <<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< var2;
}

We can see that:

Function foo defines return value is a reference, therefore it will take the implicit pointer of var1 as we called foo(var1). And it play a role as l-value.

Meanwhile, function foo2 defined returning value as a value and so it can’t play a role as l-value, only r-value.

As a result, the given script returns:

var1 = 4 var2 = 5
var1 = 5 var2 = 6
var1 = 8 var2 = 6

Overloading operators <>

Overloading operators << and >> are quite complicated, at least for me. However, after considering carefully, I realize that it’s not so teriffy. Let’s analyze the following example.

// Example program
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
class PersonInfo{
 private:
    string m_name;
    int m_age;
    string m_job;
 public:
    PersonInfo(string name = "Alex", int age = 70, string job = "Football Manager"): m_name(name), m_age(age), m_job(job){}
    friend ostream& operator<< (ostream & out, const PersonInfo & pi);
};
ostream& operator<< (ostream & out, const PersonInfo & pi){
    out << " { Name = " << pi.m_name << " age= " << pi.m_age << " job = " << pi.m_job << " } ";
    return out;
}
int main()
{
    PersonInfo pi1("Giss", 40, "Football Manager"), pi2("Messi", 30, "Footballer");
    cout << pi1 << pi2 <<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< endl;
}

FRIEND CLASSES

Some classes are friend to other classes, it means they can access even private data member of other class. Let’s exam the following script to figure out the concept.

// Example program
#include &lt;iostream&gt;
#include &lt;math.h&gt;
using namespace std;
class Coord;
class Display{
 public:
    Display(){}
    void show(const Coord&amp; t);
};
class Display2;
class Coord{
 private:
    double m_dx, m_dy;
 public:
    Coord(double dx = .0, double dy = .0){
        m_dx = dx;
        m_dy = dy;
    }
    friend double getDistance(const Coord&amp; t);
    friend Coord addPoint(const Coord&amp; t1, const Coord&amp; t2);
    friend Display2;
    friend void Display::show(const Coord&amp; t);
};
class Display2{
 public:
    Display2(){}
    void show(const Coord&amp; t){
        printf("[ %3.1f , %3.1f ] \n",t.m_dx,t.m_dy);
    }
};
double getDistance(const Coord&amp; t){
    return pow(t.m_dx*t.m_dx + t.m_dy*t.m_dy,.5);
}
Coord addPoint(const Coord&amp; t1, const Coord&amp; t2){
    return Coord(t1.m_dx + t2.m_dx, t1.m_dy + t2.m_dy);
}
void Display::show(const Coord&amp; t){
    printf("{ %3.1f , %3.1f } \n",t.m_dx,t.m_dy);
}
int main()
{
    Coord t1(3,4), t2(6,8);
    printf("%3.1f\n", getDistance(t1));
    printf("%3.1f\n", getDistance(addPoint(t1,t2)));
    Display2 d1;
    Display d;
    d1.show(t1);
    d.show(t1);
}&lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&lt;/span&gt;

This example tells  a quite completed story about friend classes.

Class Display2 is a friend class of Coord while member function Display::show() is a friend function of Coord.

Note: class Display declares  a function that has an argument of class Coord, therefore before its definition we need to declare Coord. However the function show that access data members of Coord is only defined after Coord definition.

FRIEND FUNCTIONS

This a function that is NOT a function member of a CLASS but has a right to access all data member of it. For example, the following friend functions: one just prints data member and another add two objects of a class.

// Example program
#include <iostream>
using namespace std;
class Trial{
 private:
    int m_a;
 public:
    Trial(int a=0){
        m_a = a;
    }
    void setValue(int a){
        m_a = a;
    }
    friend int getValue(const Trial& t){
        return t.m_a;
    }
    friend Trial addT(const Trial& t1, const Trial& t2){
        return Trial(t1.m_a + t2.m_a);
    }
};

int main()
{
    Trial t1(4), t2(5);
    printf("%d\n", getValue(t1));
    printf("%d\n", getValue(addT(t1,t2)));
}

As we can see , friend function can getValue can access private member data of class Trial.

CONSTRUCTOR – ERROR-PRONE

Constructor is neccessary element of any classes. It’s basic stuff. However, there is a case when errors encountered and we find it difficult to debug. Here is one of them.

// Example program
#include
using namespace std;
class Trial{
private:
int m_a;
public:
Trial(int a){
m_a = a;
}
int getValue() const {
return m_a;
}
void setValue(int a){
m_a = a;
}
};

int main()
{
Trial t;
t.setValue(3);
printf("%d",t.getValue());
}

It will cause an error because when we create an object of class Trial without initialization list, it need a DEFAULT CONSTRUCTOR, but we forgot to define it. To solve this problem, there is very simple way. Here you are:


// Example program
#include <iostream>
using namespace std;
class Trial{
private:
int m_a;
public:
Trial(int a=0){
m_a = a;
}
int getValue() const {
return m_a;
}
void setValue(int a){
m_a = a;
}
};

int main()
{
Trial t;
t.setValue(3);
printf("%d",t.getValue());
}

Sorting algorithms

#include <iostream>
using namespace std;
// ascending order
template<class T>
bool ascending(T first, T second){
	return first<=second;
}
// descending order
template<class T>
bool descending(T first, T second){
	return first>=second;
}
// swap two elements of a given array
template<class T>
void swap(T arr[],unsigned ii,unsigned jj){
	T temp;
	temp=arr[ii];
	arr[ii]=arr[jj];
	arr[jj]=temp;
}
// bubble sort
/*
The idea is: For a particular ii, compare it with all the next element, if there is any element that breaks out the expected order than swap positions
*/
template<class T>
void bubbleSort(T arr[],unsigned size,bool(*comparison)(T,T)){
	for (unsigned ii=0;ii<size-1;++ii){
		for (unsigned jj=ii+1;jj<size;++jj){
			if (!comparison(arr[ii],arr[jj])) swap(arr,ii,jj);
		}
	}
}
// insertion sort
/*
The idea is: For a particular ii, compare it with the previous subarray
*/
template<class T>
void insertionSort(T arr[],unsigned size,bool(*comparison)(T,T)){
	for(unsigned ii=0;ii<size;++ii){ 		unsigned jj=ii; 		while (jj>0){
			if (!comparison(arr[jj-1],arr[jj])) swap(arr,jj-1,jj);
			jj--;
		}
	}
}
// selection sort
/*
The idea is: For a particular ii, seek for the min(max) of the subarray after it, if the found element is different from ii, then swap
*/
template<class T>
void selectionSort(T arr[],unsigned size,bool(*comparison)(T,T)){
	for(unsigned ii=0;ii<size-1;++ii){
		unsigned iMin=ii;
		for (unsigned jj=ii+1;jj<size;++jj){
			if (!comparison(arr[iMin],arr[jj])) iMin=jj;
		}
		if (iMin!=ii) swap(arr,iMin,ii);
	}
}
//merge sort
/*
The idea is: divide and conquer.
*/
// merge function
template<class T>
void merge(T arr[],unsigned start,unsigned mid,unsigned end){
	unsigned ii(start),jj(mid+1),kk(0);
	T temp[end-start+1];
	while (ii<=mid && jj<=end){
		if (arr[ii]<arr[jj]){
			temp[kk]=arr[ii];
			ii++;
		}else{
			temp[kk]=arr[jj];
			jj++;
		}
		kk++;
	}
	if (ii<=mid){
		for (unsigned tt=ii;tt<=mid;++tt,++kk){
			temp[kk]=arr[tt];
		}
	}
	if (jj<=end){
		for(unsigned tt=jj;tt<=end;++tt,++kk){
			temp[kk]=arr[tt];
		}
	}
	for (unsigned tt=0;tt<kk;++tt){
		arr[start+tt]=temp[tt];
	}
}
// recursion function
template<class T>
void mergeSort(T arr[],unsigned start,unsigned end){
	if (start<end){
		unsigned mid=(start+end)/2;
		mergeSort(arr,start,mid);
		mergeSort(arr,mid+1,end);
		merge(arr,start,mid,end);
	}
}
// Shell sort
/*
The idea is: Develop from insertion sort and use gap to avoid moving too far
*/
template<class T>
void shellSort(T arr[],unsigned size){
	for (unsigned gap=size/2;gap>0;gap/=2){
		cout<<"ga="<<gap<<endl;
		for (unsigned ii=gap;ii<size;++ii){
			cout<<"ii="<<ii<<endl; 			T temp=arr[ii]; 			unsigned jj; 			for(jj=ii;jj>=gap && arr[jj-gap]>temp;jj-=gap){
				cout<<"jj="<<jj<<endl;
				arr[jj]=arr[jj-gap];
			}
			arr[jj]=temp;
		}
	}
}