Tag Archive : c++

/ c++

Implementation of Delegates in C++11

December 5, 2015 | Article | 1 Comment

Introduction

In C++, it would be useful to be able to bind an object with its member function and produce a global function. Such features exists in other languages, for example C#. In C++, there are member function pointers but they do not provide the feature we talk about. In this article we will discuss about a simple implementation of delegates in C++ using member function pointers and C++11 using variadic templates.

For this article, I use:

  1. Slackware64 14.0 with gcc 4.7.1
  2. Windows 8 with Visual Studio 2010 express

Background

The approach is to provide a function create_delegate, which can be called in one of the following ways:

  • create_delegate(&object, &member_function)
  • create_delegate(&function)

The first option creates an object with a member operator() that can be called as a function. The second produces a function pointer, which is the same as &function. Both these values are compatible with type type function<...>.

A Sample Program

Let’s define a class with several methods

class A {
	int i;
public:
	A(int k):i(k) {}

	auto get()const ->int { return i; }
	auto set(int v)->void { i = v; }

	auto inc(int g)->int& { i+=g; return i; }
	auto incp(int& g)->int& { g+=i; return g; }

	auto f5 (int a1, int a2, int a3, int a4, int a5)const ->int {
		return i+a1+a2+a3+a4+a5;
	}

	auto set_sum4(int &k, int a1, int a2, int a3, int a4)->void {
		i+=a1+a2+a3+a4;
		k = i;
	}

	auto f8 (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const ->int {
		return i+a1+a2+a3+a4+a5+a6+a7+a8;
	}

	static auto sqr(double x)->double { return x*x; }

	auto g1(const int& n)->void { std::cout << "g1: " << n <<  std::endl; }
	auto g2(int&& n)->void { std::cout << "g2: " << n <<  std::endl; }
	auto g3(int& n)->int&  { n++; return n; }
	auto g4(int n)-<int    { return 10*n; }
};

Please note that in source code above we use C++11 convention using auto and new function declaration syntax. It is not absolutely a requirement to do so, hence you can also define the class using traditional way of declaration like good all C++ program.

In the program, we can create a class as follows:

A a(11)

Now, to create delegates:

[sourcecode language="c++"]
auto set1 = create_delegate(&a,&A::set);
auto inc = create_delegate(&a,&aA::inc);
std::function<int(int&)> incp = create_delegate(&a,&A::incp);
auto af5  = create_delegate(&a,&A::f5);
auto set_sum4= create_delegate(&a,&A::set_sum4);
auto af8  = create_delegate(&a,&A::f8);
auto sqr = create_delegate(&A::sqr); // static function, not a member
auto g1  = create_delegate(&a,&A::g1);
auto g2  = create_delegate(&a,&A::g2);
auto g3  = create_delegate(&a,&A::g3);
auto g4  = create_delegate(&a,&A::g4);
[/sourcecode]

As demonstrated, we can use auto or function<…>. Now we can invoke the delegates:

set1(25);
int x = 5;
int k = inc(x);
int k2 = incp(x);
k2 *= 7;
std::cout << "a.get():" << a.get() << std::endl;
std::cout << "k: " << k << std::endl;
std::cout << "x: " << x << std::endl;
std::cout << "af5(1,2,3,4,5): " << af5(1,2,3,4,5) << std::endl;

set_sum4(x,1,2,3,20);
std::cout << "after set_sum4(x,1,2,3,20)" << std::endl;
std::cout << "a.get(): " << a.get() << std::endl;
std::cout << "x: " << x << std::endl;
std::cout << "af8(1,2,3,4,5,6,7,8): " << af8(1,2,3,4,5,6,7,8) << std::endl;
std::cout << "sqr(2.1): " << sqr(2.1) << std::endl;
g1(100);
g2(32+5);
int p = 15;
int& g = g3(p);
int s = g4(35);
g++;
std::cout << "p: " << p << std::endl;
std::cout << "s: " << s << std::endl;

The program will print:

a.get():30
k: 30
x: 35
af5(1,2,3,4,5): 45
after set_sum4(x,1,2,3,20)
a.get(): 56
x: 56
af8(1,2,3,4,5,6,7,8): 92
sqr(2.1): 4.41
g1: 100
g2: 37
p: 17
s: 350

Points about the implementation

For a simple member function that is not volatile or const, the implementation would be very simple. We have to create a class that will store the two pointers: one to the object and the other to the its member function:

template <class T, class R, class ... P>
struct  _mem_delegate {
	T* m_t;
	R  (T::*m_f)(P ...);
	_mem_delegate(T* t, R  (T::*f)(P ...) ):m_t(t),m_f(f) {}
	R operator()(P ... p) {
			return (m_t->*m_f)(p ...);
	}
};

But the return statement needs some correction. The problem is that if a function has an rvalue-reference argument (like auto g2(int&& n)->void), this will not work. Such a parameter in the body of the function is not an rvalue any more, it’s an lvalue. Then we have two options:

  1. Use forwarding return (m_t->*m_f)(std::forward<P>(p) …);
  2. Just convert using static_cast such that return (m_t->*m_f)(static_cast<P>(p) …);

Both options will work at this point. The first underlines the idea, the second is more general.

The variadic template allows us to define operator() with flexible number and types of parameters. The create_function implementation will simply return an object of this class:

template <class T, class R, class ... P>
_mem_delegate<T,R,P ...> create_delegate(T* t, R (T::*f)(P ...)) {
	_mem_delegate<T,R,P ...> d(t,f);
	return d;
}

Practically, there is needed extra three implementations to cover cases of member functions which are const, volatile and const volatile. That’s why traditional macros, using #define, are handy: they allow us to avoid rewriting the same code fragments. Here is the full implementation:

template <class F>
F* create_delegate(F* f) {
	return f;
}

#define _MEM_DELEGATES(_Q,_NAME)\
template <class T, class R, class ... P>\
struct _mem_delegate ##_NAME\
{\
	T* m_t;\
	R  (T::*m_f)(P ...) _Q;\
	_mem_delegate ##_NAME(T* t, R  (T::*f)(P ...) _Q):m_t(t),m_f(f) {}\
	R operator()(P ... p) _Q\
	{\
		return (m_t->*m_f)(std::forward<P>(p) ...);\
	}\
};\
\
template <class T, class R, class ... P>\
	_mem_delegate ##_NAME<T,R,P ...> create_delegate(T* t, R (T::*f)(P ...) _Q)\
{\
	_mem_delegate ##_NAME<T,R,P ...> d(t,f);\
	return d;\
}

_MEM_DELEGATES(,Z)
_MEM_DELEGATES(const,X)
_MEM_DELEGATES(volatile,Y)
_MEM_DELEGATES(const volatile,W)

A more meaningful example: calculating the length of a curve

In this section we will consider a sample practical problem and look at various approaches, and show some alternative methods to delegates.

Calculation of the length of a curve: global functions

The function CurveLength can be used to calculate the length of a curve, which is defined by two functions fx(t) and fy(t), where t is in the range [a,b]. The parameter n is the number of step we take, and it affects the precision.

auto CurveLength(auto (*fx)(double)->double, auto (*fy)(double)->double, double a, double b,   int n = 20000)
				 ->double
{
	double s = 0.0;
	double h = (b-a)/n;
	double t = a;
	double x0 = fx(t);
	double y0 = fy(t);
	for (int i = 0; i < n; i++) {
		t += h;
		double x1 = fx(t);
		double y1 = fy(t);
		double dx = x1-x0;
		double dy = y1-y0;
		s += sqrt(dx*dx + dy*dy);
		x0 = x1;
		y0 = y1;
	};
	return s;
}

A simple C-style approach would be to define the curves we need as global functions, and if we need to parameterize the curve we will define global variables. We look at an ellipse and a cycloid. The cycloid length is easily calculated analytically. As for the ellipse, if the a and b axes are equal, it will be a circle, otherwise its length cannot be expressed by a simple formula. Below is our definition of the two curves:

//Cycloid

double cycloid_a;
auto Cycloid_fx(double t)->double {
	return cycloid_a*(1 - cos(t));
}

auto Cycloid_fy(double t)->double {
	return cycloid_a*(t - sin(t));
}

//Ellipse
double ellipse_a;
double ellipse_b;

auto Ellipse_fx(double t)->double {
	return ellipse_a*cos(t);
}

auto Ellipse_fy(double t)->double {
	return ellipse_b*sin(t);
}

Here is a sample program to calculate their sizes:

double PI = 4*atan(1.0);

ellipse_a = 1.0;
ellipse_b = 1.0;

cycloid_a = 1.0;

std::cout << std::setprecision(10) << std::setw(10);

std::cout <<  "ellipse1: " << CurveLength(Ellipse_fx, Ellipse_fy, 0.0,2*PI) << std::endl;
std::cout <<  "cycloid1: " << CurveLength(Cycloid_fx, Cycloid_fy, 0.0,2*PI) << std::endl;

ellipse_a = 3.0;
ellipse_b = 1.0;

cycloid_a = 5.0;

std::cout <<  "ellipse2: " << CurveLength(Ellipse_fx, Ellipse_fy, 0.0,2*PI) << std::endl;
std::cout <<  "cycloid2: " << CurveLength(Cycloid_fx, Cycloid_fy, 0.0,2*PI) << std::endl;

 

The program will print:

ellipse1: 6.283185281
cycloid1: 7.999999992
ellipse2: 13.36489317
cycloid2: 39.99999996

The disadvantage of this approach is that all functions and their parameters are global.

An abstract class and virtual functions

A traditional, good C++ approach is to use an abstract class and define a member function CurveLength, which uses the member functions fx(t) and fy(t):

class Curve {
public:
	virtual auto fx(double t)->double = 0;
	virtual auto fy(double t)->double = 0;

	auto CurveLength(double a, double b, int n = 20000)->double {
		double s = 0.0;
		double h = (b-a)/n;
		double t = a;
		double x0 = fx(t);
		double y0 = fy(t);
		for (int i = 0; i < n; i++) {
			t += h;
			double x1 = fx(t);
			double y1 = fy(t);
			double dx = x1-x0;
			double dy = y1-y0;
			s += sqrt(dx*dx + dy*dy);
			x0 = x1;
			y0 = y1;
		}
		return s;
	}
};

class Cycloid: public Curve {
	double m_a;
public:
	Cycloid(double a):m_a(a) {}

	virtual auto fx(double t)->double {
		return m_a*(1 - cos(t));
	}

	virtual auto fy(double t)->double {
		return m_a*(t - sin(t));
	}
};

class Ellipse: public Curve
{
	double m_a;
	double m_b;
public:
    Ellipse(double a, double b):m_a(a),m_b(b) {}

	virtual auto fx(double t)->double {
		return m_a*cos(t);
    }

	virtual auto fy(double t)->double {
		return m_b*sin(t);
	}
};

The program will look like this:

double PI = 4*atan(1.0);

Ellipse ellipse1(1.0,1.0);
Cycloid cycloid1(1.0);

std::cout << std::setprecision(10) << std::setw(10);

std::cout <<  "ellipse1: " << ellipse1.CurveLength(0.0,2*PI) << std::endl;
std::cout <<  "cycloid1: " << cycloid1.CurveLength(0.0,2*PI) << std::endl;

Ellipse ellipse2(3.0,1.0);
Cycloid cycloid2(5.0);

std::cout <<  "ellipse2: " << ellipse1.CurveLength(0.0,2*PI) << std::endl;
std::cout <<  "cycloid2: " << cycloid1.CurveLength(0.0,2*PI) << std::endl;

 

The problem is that all the curves have to be derived from the same base class, and if we want to use CurveLength in a library the class Curve should be part of it.

Using delegates

Delegates allow us to deal with unrelated classes. Here is the approach using delegates:

auto CurveLength(std::function<double(double)> fx, std::function<double(double)> fy, double a, double b, int n = 20000)->double {
	double s = 0.0;
	double h = (b-a)/n;
	double t = a;
	double x0 = fx(t);
	double y0 = fy(t);
	for (int i = 0; i < n; i++) {
		t += h;
		double x1 = fx(t);
		double y1 = fy(t);
		double dx = x1-x0;
		double dy = y1-y0;
		s += sqrt(dx*dx + dy*dy);
		x0 = x1;
		y0 = y1;
	}
	return s;
}

double PI = 4.0*atan(1.0);

class Cycloid {
	double m_a;
public:
	Cycloid(double a):m_a(a) {}

	auto fx(double t)->double {
		return m_a*(1 - cos(t));
	}

	auto fy(double t)->double {
		return m_a*(t - sin(t));
	}
};

class Ellipse {
	double m_a;
	double m_b;
public:
	Ellipse(double a, double b):m_a(a),m_b(b) {}

	auto getX(double t)->double {
		return m_a*cos(t);
	}

	auto getY(double t)->double {
		return m_b*sin(t);
	}
};

 

I have deliberately given different names to member functions. These two classes are unrelated. Here is a program:

int main() {
	Ellipse ellipse1(1.0,1.0);
	Cycloid cycloid1(1.0);

	auto ellipse1_fx = create_delegate(&ellipse1,&Ellipse::getX);
	auto ellipse1_fy = create_delegate(&ellipse1,&Ellipse::getY);
	auto cycloid1_fx = create_delegate(&cycloid1,&Cycloid::fx);
	auto cycloid1_fy = create_delegate(&cycloid1,&Cycloid::fy);

	std::cout << std::setprecision(10) << std::setw(10);

	std::cout <<  "ellipse1: " << CurveLength(ellipse1_fx, ellipse1_fy, 0.0,2*PI) << std::endl;
	std::cout <<  "cycloid1: " << CurveLength(cycloid1_fx, cycloid1_fy, 0.0,2*PI) << std::endl;

	Ellipse ellipse2(3.0,1.0);
	Cycloid cycloid2(5.0);
	auto ellipse2_fx = create_delegate(&ellipse2,&Ellipse::getX);
	auto ellipse2_fy = create_delegate(&ellipse2,&Ellipse::getY);
	auto cycloid2_fx = create_delegate(&cycloid2,&Cycloid::fx);
	auto cycloid2_fy = create_delegate(&cycloid2,&Cycloid::fy);

	std::cout <<  "ellipse2: " << CurveLength(ellipse2_fx, ellipse2_fy, 0.0,2*PI) << std::endl;
	std::cout <<  "cycloid2: " << CurveLength(cycloid2_fx, cycloid2_fy, 0.0,2*PI) << std::endl;

	return 0;
}

 

Delegates allow us to use the same functions for various curve classes, which are completely unrelated. This CurveLength can be part of the library.

An alternative approach: using lambdas

The C++11 lambdas make it possible to define functions immediately and also to capture the variables from the environment. The CurveLength and the curve classes can be defined exactly the same as in the example with delegates, but the program, the function calls change:

int main() {
	Ellipse ellipse1(1.0,1.0);
	Cycloid cycloid1(1.0);

	auto ellipse1_fx = create_delegate(&ellipse1,&Ellipse::getX);
	auto ellipse1_fy = create_delegate(&ellipse1,&Ellipse::getY);
	auto cycloid1_fx = create_delegate(&cycloid1,&Cycloid::fx);
	auto cycloid1_fy = create_delegate(&cycloid1,&Cycloid::fy);

	std::cout << std::setprecision(10) << std::setw(10);

	std::cout <<  "ellipse1: " << CurveLength(ellipse1_fx, ellipse1_fy, 0.0,2*PI) << std::endl;
	std::cout <<  "cycloid1: " << CurveLength(cycloid1_fx, cycloid1_fy, 0.0,2*PI) << std::endl;

	Ellipse ellipse2(3.0,1.0);
	Cycloid cycloid2(5.0);
	auto ellipse2_fx = create_delegate(&ellipse2,&Ellipse::getX);
	auto ellipse2_fy = create_delegate(&ellipse2,&Ellipse::getY);
	auto cycloid2_fx = create_delegate(&cycloid2,&Cycloid::fx);
	auto cycloid2_fy = create_delegate(&cycloid2,&Cycloid::fy);

	std::cout <<  "ellipse2: " << CurveLength(ellipse2_fx, ellipse2_fy, 0.0,2*PI) << std::endl;
	std::cout <<  "cycloid2: " << CurveLength(cycloid2_fx, cycloid2_fy, 0.0,2*PI) << std::endl;

	return 0;
}

I deliberately show two approaches to capture variables: a specific one [&ellipse1] , and general [&]. Either can be used. Lambdas are easy to use, but syntax becomes longer if you have to deal with more parameters. In the end, it’s your choice.

Installing MPICH from Source for Slackware64

December 5, 2015 | Article | 1 Comment

MPI CH is a high performance and widely portable implementation of the Message Passing Interface (MPI) standard. The original implementation was based on the Chameleon portability system to provide a light-weight implementation layer (hence the name MPICH from MPI over CHameleon).

Message Passing Interface itself is a system designed by a group of researchers from academica and industry to function on a wide variety in parallel computers.The standard defines the syntax and semantics of a core routines useful to a wide range of users writing protable message-passing programs in Fortran77 or the C programming language.

The goals of MPICH are:

  1. to provide an MPI implementation that efficiently supports different computation and communication platforms including commodity clusters (desktop systems, shared-memory systems, multicore architectures), high-speed networks and proprietary high-end computing systems (Blue Gene, Cray)
  2. to enable cutting-edge research in MPI through an easy-to-extend modular framework for other derived implementations

MPICH is distributed as source (with an open-source, freely available license). It has been tested on several platforms, including Linux (on IA32 and x86-64), Mac OS/X (PowerPC and Intel), Solaris (32- and 64-bit), and Windows. Please see the README, CHANGES, and RELEASE_NOTES files in the distribution for more details.

This article will cover about compiling and installing latest MPICH for Linux Slackware64.

Obtain the Materials

The latest version (per February 13th, 2013) is 3.0.2. To build the program sure we need the source. Download it from MPICH site or direct download from here.

Installation

Now we will extract, make the program, and later install it. Do the following:

cd mpich-3.0.2
./configure
make
make install

To check whether you have successfully install mpich, invoke this command on your terminal:

mpicc --version

Which you will be prompted with your gcc version. Yes, MPICH use gcc, or another compiler if you set so, to compile a program.

Testing

Now let’s make a simple MPI application. Copy this souce code and name it as mpi.c

#include <mpi.h>
#include <stdio.h>

int main(int argc, char** argv) {
   int size, rank;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &size);
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);

   printf("Hello world from %d of %d", rank, size);

   MPI_Finalize();

   return 0;
}

Compile it using:

mpicc -o my_mpi mpi.c

There is a special way to run MPI program. In general, we do like this:

mpirun <program name> <list of arguments>

Thus, to run our program we invoke:

mpirun my_mpi

Now, what is the result? 😀

Installing Mono to Slackware64 14.0

December 5, 2015 | Article | No Comments

Mono is a software platform designed to allow developers to easily create cross platform application. Mono is open source .NET development framework which can be built on top of Windows, Linux, Mac, iOS, and android. Based on ECMA standards for C# and the Common Language Runtime.

In this article we will discuss about installation of Mono for Linux Slackware64 14.0. But actually this is generic instruction and you can do it on any Linux, even BSD or Solaris if you have appropriate tools.

For this article I will use:

  1. Slackware64 14.0
  2. Mono 3 latest
  3. Mono 2

The method we will use is installation from source using source code downloaded from Github. As you might see, in this process we also need mono 2. It might seems odd but for compilation mono 3,  mono 2 is required. That’s why we will have to install mono 2 at least until compilation.

Obtain the Materials

Prepare a directory for storing source code and also for build purpose. Let say ~/nestmono/

The source code for mono 3 can be obtain from their github. To download it, open terminal and invoke following commands:

git clone https://github.com/mono/mono.git

At this point we have a directory named mono

Like I said before, we need mono-2 to compile mono-3. You can download the binary from Mono’s official site. But official site doesn’t offer native installation for Slackware. As alternative, we can install mono using following link. Or use Mono to download previous version of mono on compilation time.

Compilation

First install mono-2. Assuming we have download mono-2 with package filename: mono-2.10.5-x86_64-1sl.txz. We do binary installation at this point.

installpkg mono-2.10.5-x86_64-1sl.txz

Now go to our build directory and head to mono subdirectory. In this article, Mono would be installed to /usr/local. If you want to change the location, replace /usr/local path with any path you wish. Do following on terminal:

./autogen.sh --prefix=/usr/local
make
make install

If you prefer not to download mono-2 by yourself and using mono-3 to download mono-2 before compilation, then after invoking autogen.sh and before make do following:

make get-monolite-latest
make EXTERNAL_MCS="${PWD}/mcs/class/lib/monolite/gmcs.exe"

The process might take some times. At this point you should be success on installing Mono. We now should have C# compiler and runtime library. You might also remove mono-2 if you want. To do so, go to where we store mono-2 package and do following (using assumption you install mono-2.10.5 like we did earlier):

removepkg mono-2.10.5-x86_64-1sl.txz

Let’s check if mono is properly installed. Create a C# source file and name it mono.cs (or anything you like). Write this to the source:

using System;

public class HelloWorld {
  static public void Main () {
    Console.WriteLine ("Xathrya said: Hello Mono!");
  }
}

To compile use gmcs. The compilation of mono.cs will produce mono.exe which can be run using mono:

gmcs mono.cs
mono mono.exe

If successful, you will see this text: Xathrya said: Hello Mono!

If gmcs is not recognized (mostly because your mono installation path is not on $PATH environment variable) you can do one of following: make a static link or include to $PATH.

For static linking you can use:

ln -s /bin/gmcs /usr/local/bin/gmcs

For Manual path inclusion you add this to your ~/.bashrc (if you use bash):

export PATH=$PATH:/bin/gmcs

Personally I like using static linking. But since I installed gmcs on /usr/local (which mono and gmcs is in /usr/local/bin) and /usr/local/bin is inside of $PATH, I don’t need to create symbolic linking or expand environment variable.

Beginning C++: Operators

December 3, 2015 | Article | No Comments

When writing a program we are often demanded to define operations, either calculations, comparison, etc. To do it we need operators and C++ has a complete arsenal that can be used. In this article we will divide our focus into some subjects: assignment operator, unary operators, binary operators, ternary operators.

Assignment Operator

Assignment is a operator for storing a value into a variable or a constant. This operator is symbolized by equal sign (=). Let’s take a look of it in this snippet:

#include <iostream>
using namespace std;

int main() {
	// when declaring a constant we have to assign a value immediately.
	const float PHI = 3.14;

	// declaring variables
	char myChar;
	int myInt;
	double myDouble;

	// assign each variable
	myChar = 'A';
	myInt = 135;
	myDouble = 21.0378;

	// print out the value of each variable
	cout<<myChar<<endl;
	cout<<myInt<<endl;
	cout<<myDouble<<endl;
	return 0;
}

Unary Operator

An unary operator is an operator which only has one operand for the operation. These type of operator has following operators:

Operator Operations Example
+ Make a number become positive +7
Make a number become negative -7
++ Increment C++
Decrement C–

An increment is an incremental of a value on a variable by one. For example a variable C initially has value 4 and we do incrementing it then the value of C now become 5. Similar with increment, a decrement take a variable and do decremental of a value by one. Thus, when C is initially has value 4 and we do decrementing then the value of C will become 3.

There are to type of increment and decrement: pre and post. Both will have same result in the end but they are different in operation.

The pre- (either increment or decrement) would do value-changing first before being used. While in post- (either increment or decrement) the value is changed after being used.

Let’s take a look of how the concept mean:

#include <iostream>
using namespace std;

int main() {
	int x = 5;
	int y = 5;

	cout<	cout<	cout<
	x = 5;

	cout<	cout<	cout<
	cout<	cout<	cout<
	y = 5;

	cout<	cout<	cout<
	return 0;
}

Binary Operator

In mathematics, a binary operator is an operator which has two operand for its operation. In C++, we divide binary operators into smaller categories: arithmetic operators, logic operators, relational operators, and bitwise operators.

Arithmetic Operator

Arithmetic operators are operators used for computing and calculating a value from another value. Like what we have learned from school, we know there are some operators in mathematics and we have it too on C++:

Operator Operations Example
+ Addition 2 + 7 = 9
Reduction 3 – 1 = 2
* Multiplication 3 * 5 = 15
/ Division 6 / 3 = 2
% Modulo 11 % 3 = 2

You must be familiar with +, -, *, and / operator. But please note for / operator, this operator will result on integer value if both of operands are integers. So if you have a = 5 and b = 2 and do a / b, instead of 2.5 you will get 2. To get a real value, you must supply one of operand (either numerator or denominator) with real-valued number.

Some of you maybe aren’t familiar with modulo operation. In simple way, a modulo operation will give an integer for remainder of division. Let’s take example from the table. We have two number, 11 and 3. When we divide 11 with 3, resulting in 3 and has remainder 2 (number that can’t be divided by 3). The modulo operation will give value 2 as a result. Another example: 6 % 4 will give 2, 19 % 5 will give 4, etc.

Logical Operators

Logical operator is an operator used for operation in which resulting only two distinct value: true or false. It is corresponded with boolean value in previous discussion. There are three operators on this category:

Operator Operations Example
&& AND true && true = true
|| OR true || false = true
! NOT NOT false = true
&& (AND) Operator

AND operation will give true only if both of operands are true. Either from that, this operator will give false. Let’s look at this truth table:

X Y X && Y
1 1 1
1 0 0
0 1 0
0 0 0

Remember that false is represented by zero and true is represented by not-zero value.

|| (OR) Operator

OR operation will give result true if one of operands has true value. Let’s see the truth table below:

X Y X || Y
1 1 1
1 0 1
0 1 1
0 0 0
! (NOT) Operator

Value of NOT operation is an inverse of the operand. Well, actually this operator is an unary operator, but for the sake of simplicity I group it with the rest of logical operators. Let’s look at the truth table:

X ! X
1 0
0 1
Relational Operators

A relational operator is an operation to determine relation between two operands. These operators are simply comparison between two operands.

Operator Operations Example
< Less than (5 < 2) = 0
> Greater than (5 > 2) = 1
<= Less than or equal (3 <= 2) = 0
>= Greater than or equal (3 >= 2) = 1
== Equal (3 == 3) = 1
!= Not equal (3 != 3) = 0

Please note that equal operator is consists of two = symbol.

Bit-wise Operators

Unlikely other programming language, C++ support bit-wise operations. A bit-wise operations used for operation of bit manipulation. Let’s take a look for the this table.

Operator Operations Example
& AND 1 & 0 = 0
| OR 1 | 0 = 1
^ Exclusive-OR (XOR) 1 ^ 1 = 0
~ NOT ~1 = 0
<< Left Shift 5 << 1 = 10
>> Right Shift 10 >> 1 = 5

At glance you might think that these operations are similar to logical operators. Well, that’s true in some way. In bit-wise operation, the operand are every bit on both side while the logical operator use whole number as operand and both operand act only as two distinct value true or false.

Let’s take example for counterparts AND: Suppose we have two number, 5 and 2. In logical operator, both 5 and 2 are treated as true this 5 && 2 will give result true. While in bit-wise operation, we treat 5 and 2 as bits which we have 5 = 00000101 and 2 = 00000010. Then, bit-wise AND would result on:

5 00000101
2 00000010
———— &
5 & 2 00000000

Now, as you can see. We do AND operation for each bit and got result 0. With similar operation we will get 2 when we operating 6 and 2 (guess why?).

An exclusive-OR operation is bit-wise operator which similar to bit-wise OR operator. But it only gives 1 if only one operand is 1 (and other is 0). Otherwise it will give 0.

The interesting part is shifting. Shift operation, like the name, is an operation to shift the bit to a direction, The number that would be shifted is the left operand and it will be shift to x place as given by right operand. Let’s look example for left and right shift.

A left shift (a << b) will shift a to b position in left. Suppose we have two number, 5 = 00000101 and 2 and did left shift like this: 5 << 2, the bits of 5 would be shift in a way that result in 00010100 = 20. Note that the result bit is actually shifted 2 position from previous one.

A right shift (a >> b) will shift a to b position in left. Suppose we have two number, 4 = 00000100 and 2 and did the right shift like this: 4 >> 2, the bits of 4 would be shift in a way that result in 00000001 = 1. Note that the result bit is actually shift 2 position form previous one.

Ternary Operator

Ternary operator is an operator which has 3 operands for operation. It seems odd but the operator consists of 2 symbols ? and :. General scheme for this operator is given below:

expression1 ? expression2 : expression3;

This operator consist of 2 stage: checking and executing. First it will check the condition on expression1. If expression1 result in true, the expression2 will be executed. If not, the operator will execute expression3. Now let’s take a look of this snippet:

#include <iostream>
using namespace std;

int main() {
	// declare 2 variables, x with random-initialized value and y with initial value 5
	int x, y = 5;

	// check if y > 0. It would be true so we have -y as a result of this operation
	x = (y > 0) ? -y : y;

	// Let's make sure the result is same as our prediction
	cout<< x <<endl;
}

 

Beginning C++: Primitive Types and Identifiers

December 3, 2015 | Article | No Comments

What is Identifiers?

Literally, identifiers are tokens / symbols used to identify objects declared in program. Compiler knows object through identifier. Identifier can be a variable name, constants, functions, classes, template, even namespace.

In this article we will discuss identifiers in the smaller scope: variables and constants.

Identifier act as variable (or constant) is a value-container. Both of them can save some values but they are differ in the term of how they save value. A constant can save value but it can only assigned once and the value cannot be modified at runtime. While a variable can save value and the value can be modified or changed at runtime.

Let’s save it up for later and see this little analogy:

Imagine variable and constant as a bottle. We know that a bottle is a container which can contain / save something (especially liquid). Now, the bottle has many types / kinds, such as: soysauce bottle, water bottle, kerosene bottle, gas bottle, etc. Each bottle can save specific type liquid. For example a water bottle can only save water. Imagine there is a mineral-water bottle but it contains kerosene. It’s not suitable and maybe it can bring harm later (if someone think it as a plain water and drink them, you can imagine what will come next).

From the same perspective, variables and constant do so. A variables can save a value. The values can vary but the variable can only hold one specific type of value. We can only set what kind of value the bottle can hold only at declaration. A variable can be “refilled” with another value as long as the value has same data type while a constant is cannot be refilled with another value.

Primitive Data Types

As discussed, either variables or constant can save value. But they can only save value with the same type as they are declared before. The set of values of data which variable can sabe is referred as data types. There are two types of data types: a primitive data types and user-defined data types. For this article we will focus on primitive data types.

What is primitive data type? It is a built in / native data type on C++ programming language. So far, there are four primitive data types supported on C++: integer number, real number, character, boolean. Advancing to next level, we can create a new data type using these primitive data types (let say the primitive data types are the building block to build more complex one) through enumeration process, struct, and class.

Now, how can we declare a variable?

A syntax to declare a variable is as follow:

data_type variable_name;

A data_type is a data type. It can be user-defined data type or primitive data types. While the variable_name is a variable name, an identifier.

How about a constant?

Constant declaration is similiar to variable declaration, except at the declaration the constant must be initialized with some value and preceded by keyword const.

const data_type variable_name = value;

Now let’s write the actual code with variable and constant declaration

#include <iostream>
using namespace std;

int main() {
	// declaring variables
	int i;
	float f;
	char c;
	bool b;

	// declaring constants
	const int j = 10;
	const float k = 3.14;
	const char l = 'A';
	const bool m = true;

	return 0;
}

From codes above, we have four variables: an integer variable named i, a real-value variable name f, a character variable name c, a boolean variable name b. We also have four constant: an integer constant namej, a real-value constant name k, a character constant name l, a bool constant name m.

We can’t write identifier arbitrary. There are some rules to naming an identifier. Here are the rules for naming identifier:

  • Identifier can’t be chosen from C++ reserved keyword. C++ has reserved keywords such as: for, do, while, int, float, return, etc and pick them for identifier name is strictly forbidden.
  • Identifier name is case sensitive. When you say aVariable and AVARIABLE, C++ distinguish them because they have different case although they are consist of same word.
  • Identifier name must be unique. You cannot declare two variable with totally same name even if the identifier has different data type.
  • Identifier name consists of alphabet, number, or underscore. Any character beside that is considered as invalid name. No symbolic character such as: #, @, ?, !, $, as identifier.
  • Identifier name cannot be preceded by number. Identifier can only preceded by underscore (_) and alphabets. Number can be used as identifier name, but it cannot be placed as first character.
  • Identifier cannot has space.

The Identifier Scope

The lifetime of an identifier, or in some terms the scope where an identifier can be resolved. There are two scope: global and local. This is applied to both variables and constants.

A global variable or constant, is a variable or constant declared outside of any blocks of code. Simply we can say a global variable is placed outside of any function. A global identifier is recognized in whole source code.

A Local variable or constant, is a variable or constant declared inside of a block of code. Simply we can say a local variable is place inside of a function, branching code, looping code, etc. This identifier is recognized only at declared blocks.

Outside from two identifier types, a variable can also be classified as static variable. A static variable is a variable which occupy computer memory permanently (until the program is unloaded). It means the last variable value will be kept. To declare a static variable we can write as:

static data_type identifier_name;

Similiar to normal variable, static variable can be categorized as local-static variable and global-static variable.

Another variable type we have are register variable. A register variable will be stored on CPU register. Register variable provide faster way to store a value. No need to access memory. To declare a register variable, one must do:

register data_type variable_name;

More into Data Types

We have discussed a little thing about data type at above. Now Let’s dive deeper into data types. As stated before, C++ has four built-in primitive data types: integer number, real number, character, boolean. We will cover each category. We will refer to x86 machine.

Integer Numbers

Integer numbers, as hinted by the name, is a set of number of integers. An integer is a whole number (not a fractional number) that can be positive, negative, or zero. Data types for this category are:

Data Type Size (bits) Range
int 16 or 32 -32,768 to -32,767 or
-2,147,483,648, to 2,147,483,647
unsigned int 16 or 32 0 to 65,535 or
0 to 4,294,967,295
signed int 16 or 32 similiar to int
short int 16 -32,768 to 32,767
unsigned short int 16 0 to 65,535
signed short int 16 similiar to short int
long int 32 -2,147,483,648, to 2,147,483,647
signed long int 32 similiar to long int
unsigned long int 32 0 to 4,294,967,295

Real Numbers

Real numbers are number for real-value number. Data types for this category are:

Data Type Size (bits) Range Precision
float 32 1.2E-38 to 3.4E+38 6 digits
double 64 2.3E-308 to 1.7E+308 15 digits
long double 80 3.4E-4932 to 1.1E+4932 19 digits

Character (and string)

Character are data type used for representing a character on computer. Character is based on ASCII. Inside a computer, a character is stored as number representation but it would be presented as a character. A series of character can form a string. A string is defined as sequence of characters and terminated by NULL character. This category has following data types:

Data Type Size (bits) Range
char 8 -128 to 127 or 0 to 255
unsigned char 8 0 to 255
signed char 8 -128 to 127

A string in other hand is formed by series of character. For example, if a single character is ‘A’, a string can be something like “Hello world” or “Learning C++ with Xathrya”.

Boolean

Often said as logic data type. It has only one data type, bool which has 2 different value: false (can be represented as 0) and true (can be represented as any number except 0). This data type mainly represent condition of comparison either by operator equality, inequality, greater, less.

Advanced C++: Namespace

December 3, 2015 | Article | No Comments

Let’s imagine a computer without directory nor subdirectory. Any single file would be stored on a single repository / warehouse only. What could it be? Many problems? Absolutely. Because there is only one place to keep file, any single file must have unique filename and unique identity. Another problem occurred when we want to find a file. Searching a file in set of thousand files, isn’t it frustrating?

With directory system (hierarchically), we are helped to organize our files into smaller modules. We can group files with same objectives / functions (for example: videos, accounting report, etc) into single directory.

The same objective goes to namespace. Namespace is C++ mechanism to group a set of file into some “folder” called namespace. With namespace we can prevent conflict of reduplication variable name, constant name, function name, and class name. A different system can still shared same name but they would be separated into different namespace.

Namespace is very useful for large program with high complexity. It means a program can be broken down and reorganize into different namespace.

Our popular namespace would be std. It is a namespace used by C++ standard library to group it’s functions, modules, and classes.

Let say we have two library, A and B. Without namespace, we can’t create two functions with same name (signature). But with namespace, both can use a same name.

Defining a Namespace

To define a namespace, we can use C++ keyword namespace.

namespace namespace_name {
	// declarations
}

As we can see, a namespace is a simply block / scope of code where every variable, constants, functions, and classes declared can only be known by member of namespace (inside only). When we called any member of namespace scope from outside, we need to write the name of namespace with scope-resolution operator (::). Here’s the example:

#include <iostream>
using namespace std;
int x;

// Defining namespace A
namespace A {
	// declare a variable
	int x = 10;

	// declare a function prototype print() inside namespace A
	void print();
}

// We implement our prototype inside namespace A
void A::print() {
	// x here is know by print() because we have introduce our function
	// print() as a member of namespace A
	cout<<"The value of x "<<x<<endl;
}

int main() {
	x = 10;
	print();
}

The codes above has tell us about how to declare variables and functions under namespace A. Now write, compile, and run the code. What is the value of x?

There are two x’s. One is x inside namespace A, the one that recognized by function print(). The other one is global variable x which is known by function main(). Where a function print() is called, it only know variable x inside the namespace namespace which make it call only. While the function main() only know variable x as global variable (the one inside namespace isn’t visible to main()). So that’s why, you would encounter either 0 or random value.

Two namespace? Let’s see the example:

namespace A {
	int x;
	void printx();
}
void A::printx() {
	cout<<"X inside namespace is "<<;x<<endl;
}
namespace B {
	int x;
	class Example {
	private:
		int number;
	public:
		void setNumber(int value) {
			number = value;
		}
		int getNumber() {
			return number;
		}
	};

	void printx() {
		cout<<"Now we have "<<x<<endl;
	}
}
int main() {
	A::printx();		// print x value inside namespace A
	A::Example ex;		// declaration of class Example

}

Using namespace

After defining a namespace, we must know how to use it inside of program. In other word we must know how to access variables, constants, functions, or even classes declared inside of namespace. To do so, there are two different approach: Scope resolution (::), keyword using.

Using scope resolution

To recall variable, constant, functions, or classes defined inside a namespace we can use operator :: (scope resolution).

namespace_name::member

Here’s the example of scope resolution usage:

#include <iostream>
using namespace std;

namespace A {
	int x;
	void setX(int value) {
		x = value;
	}
	int getX() {
		return x;
	}
}
int main() {
	// assign number to variable x outside of namespace A
	A::x = 10;
	cout<<"X has value: "<<A::x<<endl;

	// Call function setx() outside of namespace A
	A::setX(135);

	// call function getX() outside of namespace A
	cout<<X has value: "<<A::getX()<<endl;

	return 0;
}

Write, compile, and run. What’s the result?

Using keyword using.

First, let’s observe this code:

#include <iostream>

int main() {
	int number;
	std::cout<<"Input an integer: ";
	std::cin>>number;
	std::cout<<"You just entered number "<<number<<std::endl;

	return 0;
}

On codes above, we’re not giving using namespace std; like we always did. But we can still use cin, cout, and endl like we always did by giving std:: in front of them. That is, std is a namespace and to use member inside namespace std we use using namespace std clause. In general, to use whole namespace we can declare:

using namespace namespace_name;

But is there another way? Suppose we want to use std::cout only and the other is irrelevant (we do not use them). Can we just skip the others? Yes we can. In that case we are using only a single namespace member. Thus we declare something like this:

using std::cout;

In general we can use a member of namespace as:

using namespace_name::member;

Alias Namespace

If we are encounter a namespace has too long name to remember (or complicated name), we can rename it to different name. C++ help us to reduce the complexity by renaming old namespace into new space. This feature is called aliasing, or referring a new namespace to old namespace.

Here’s how you could do that:

namespace new_alias_name = old_namespace_name;

For instance, you want to rename a namespace a_very_long_namespace_to_write to be simple_namespace we can write:

namespace simple_namespace = a_very_long_namespace_to_write;

Nested Namespace

Inside namespace can be defined another namespace. This feature is called nested namespace and allow us to create namespace inside another namespace. C++ gives us capability to achieve high modularity, even for namespace.

A simple code for explaining nested namespace would be:

#include <iostream>
using namespace std;

// declaring nested namespace
namespace outer {
	int i;
	namespace inner {
		int j;
	}
}

// recall the namespace
int main() {
	// assign value of i and j
	outer::i = 10;		// correct
	// outer::j = 20; 	// wrong
	outer::inner::j = 20;	// correct

	cout<<"The value of i is"<<outer::i<<endl;
	cout<<"The value of j is"<<outer::inner::j<<endl;

	// using outer namespace name
	using namespace outer;
	i = 30;			// correct
	// j = 40;		// wrong
	inner::j = 40;		// correct

	cout<<"The value of i is"<<i<<endl;
	cout<<"The value of j is"<<inner::j<<endl;

	// using inner namespace name
	using namespace inner;
	i = 50;			// correct
	j = 60;			// correct

	cout<<"The value of i is"<<i<<endl;
	cout<<"The value of j is"<<j<<endl;

	return 0;
}

 

Now, what’s your comment?

Advanced C++: Mutable Member

December 3, 2015 | Article | No Comments

In the previous article we have discussed a const member function. A const member function is a mechanism for function to prevent it to modify a data.

In practical, const functions is needed to keep purity of class. A non privileged function is restricted to modify member variable. But sometimes we are forced to change data from const function (well, it’s so rare). To do so, we have to declare data as mutable member.

This simple code will tell us about keyword mutable:

#include <iostream>
using namespace std;

class Example {
	mutable int x;
public:
	void setX(int value) const {
		x = value;		// correct
	}
	int getX() const {
		return x;		// correct
	}
};

int main() {
	Example* p;

	p = new Example;
	p->setX(3);
	cout<<"The x has value "<<p->x<<endl;

	return 0;
}

In this example, function setX() is allowed to modify x because x is declared as mutable.

Advanced C++: Const Member-Function

November 24, 2015 | Article | 1 Comment

On C++, there is a way to declare a function inside a class (class’ method) as a constant function. If that is the case, the this pointer would be treated as constant pointer. Thus the function is restricted to modify any data inside its body.

To declare a function as a constant function, we must give a keyword const after the function header.

A simple code to give a hint for const member function:

#include <iostream>
using namespace std;

class Example {
int x;
public:
void setX(int value) const {
	x = value;        // wrong! Const functions are restricted
			  // to modify the data.
}
int getX() const {
	return x;        // correct!
}
};

int main() {
	Example* p;
	p = new Example;

	p->setX(3);
	cout<getX()<<endl;

	delete p;
	return 0;
}

Write and compile. Did you make it? You should get error if you write the code as is. The problem lies on function void setX(int value) const; Remember that a const function is restricted to modify the member variable, but a int getX() const; is still have read access to member variable.

Sometimes we need to change member variable by const function. To do this, member variable must be declared as mutable.

Maybe, template is one of C++ key feature that is rarely owned by other programming language. This feature is already supported by all modern / standard C++ compilers. Using template, we can create a single generic function or generic class. Simply we can create one general function or general class and whenever a similiar function or class is met, we can instance it with those problems.

Template is defined using C++ keyword, template.

Template is also the fundamental / the basis for creation of Standard Template Library (STL). STL is a collection of function or data structure that can be used for any data type. Yes, you can create a list of integer, a queue of float, a stack of string, etc with single class.

Function Template

Function template is a generic function. You create a function that does the job and every data can be passed to it, without recode the function.

Function Template with Generic Type

To create a function template, we did the same thing as creating a simple function. The difference lies on parameter type.

Here is the generic function template declaration.

template <class T>
return_type function_name( parameter1, parameter2, ...) {
	statements;
}

The template keyword describe that this function is generic function. While T on <class T> is called as generic type. It is a placeholder. This type then will be used as parameter declaration of that function. Let’s see a simple example:

#include <iostream>
using namespace std;

template
void SwapVariable(T& x, T& y) {
	T z;

	z = x;
	x = y;
	y = z;
}

int main() {
	int a = 10, b = 15;
	float c = 3.14, d = 1.15;

	SwapVariable(a,b);
	SwapVariable(c,d);

	cout<<a<<' '<<b<<endl;
	cout<<c<<' '<<d<<endl;
	return 0;
}

Write, compile, and run the above code. What are the output?

If you observe carefully, you can see that we only define one function SwapVariable but we use if for 2 different data type: int and float. This is the power of generic function.

Function Template with Two or More Generic type

When you see the declaration, the data type used for the argument are T. This indicated that both argument HAVE the same data type, regardless what type. How can we specify two or more different data type?

template <class T, class U>
void Writeln(T x, U y) {
	cout<<x<<' '<<y<<endl;
}

The above code is a generic function with two different generic type, T and U respectively. Those T and U can be replaced with any other type, such as: int, float, char, etc. Interesting, huh? 😀

In general, the generic types are declared inside template< >. If you want three you should declare three inside them. How about four?

template<class TYPE1, class TYPE2, class TYPE3, class TYPE4>
void aFunction(TYPE1 w, TYPE2 x, TYPE3 y, TYPE4 z) {
	// do somethings
}

Function Template Overload

Just like ordinary function, function template can be overloaded. This code will give you a hint to do so:

#include
using namespace std;

template<class TYPE1>
void writeIt(TYPE1 x) {
	cout<<x<<endl;
}

template<class TYPE1, class TYPE2>
void writeIt(TYPE1 x, TYPE2 y) {
	cout<<x<<endl;
	cout<<y<<endl;
}

int main() {
	writeIt(3);
	writeIt(1, 2.5);

	return 0;
}

See? We have overloaded writeIt function for our need.

Generally speaking, function template is used if we have generic algorithm and can be used to similiar data type. Later, the compiler will create a specific instance of function for given data type. It is done in compiler level, you just need to write once.

Class Template

Besides function template, C++ also provide Class Template. Similiar to function template. class template can be used to create generic class for any similiar functional of different type of class.

Class Template with One Generic Type

In principle, defining class template is similiar to defining ordinary class. Here is a generic class template declaration:

template <class T>
class class_name {
access specifier:
	data
	methods
};

To instantiate a class template, we have general statement like this:

class_name < data_type > instance_name;

Now let see the simple example:

#include <iostream>
using namespace std;

template<class T>
class EXAMPLE {
public:
	EXAMPLE(T xx) { x = xx; }
	void showOff() { cout<<x<
private:
	T x;
};

int main() {
	EXAMPLE<int>  A(10);
	EXAMPLE<string>  B("Xathrya Sabertooth");
	EXAMPLE<float>  C(3.14);
	EXAMPLE<char>  D('A');

	A.showOff();
	B.showOff();
	C.showOff();
	D.showOff();

	return 0;
}

compile and see the result.

Here in our example, we have EXAMPLE class with one generic type. The EXAMPLE class then can be instantiate to different object with different characteristic, A with int, B with string, C with float, D with character. Everything from a same class.

Class Template with Two or More Generic Type

Similiar to generic function declaration, a class template definition can be composed of two or more generic type. Here is a sample code of it:

#include <iostream>
using namespace std;

template<class TYPE1, class TYPE2>
class EXAMPLE {
	TYPE1 x;
	TYPE2 y;

public:
	EXAMPLE(TYPE1 xx, TYPE2 yy) {
		x = xx;
		y = yy;
	}
	void showOff() {
		cout<<x<<' '<<y<<endl;
	}
};

int main() {
	EXAMPLE<int, float>  A(15, 4.67);
	EXAMPLE<string, int>  B("Xathrya",30);

	A.showOff();
	B.showOff();
}

Write, compile, and run the code. What is the result? 😀

Template with typename keyword

In previous example we always use keyword class to define a generic type. There is another way to define a generic type, using typename class. Essentially, the declaration by class and declaration by typename is interchangable. So these declaration for function template is equivalence:

template<class T>
void function1(T t);

template<typename T>
void function2(T t);

So let’s summarize this article. What is the benefit using template?

  • Save up time: why would you write “same” code everytime? Write once for similiar condition. Besides, you can read and write fewer code 😀
  • Can be used for another situation: function and class template can be used for any data type.
  • Improving program flexibility

Beginning C++: Comments Style Guide

November 24, 2015 | Article | No Comments

Comments, believed or not, is one of important concept. It is not as crucial as logic flow in program but comment is still believed as one.

Comments are portions of the code ignored by the compiler which allow programmer to make simple notes in the relevant areas of the source code. Comments come either in block form or as single lines. It is simply ignored by compiler. But the value of comment lies as a note, a message between programmer, a reminder about piece of code, etc.

A good comment can prevent miscommunication between programmers. How can you explain your piece of code? A comment would do.

Why do I have to write a single article for just a comment? Here, in this article I want to give you a good way of writing and code. Isn’t it nice if other people can understand your code without you explain face to face by them, only by comments?. See the essential point there? Great!

Type of comments on C++

How could you write a comment on C++? There are two kinds / types: single-line and multi-line comments.

Single-line comment

A single line comment is a comment accommodated only on single line. It is start with // and continue untul the end of the line (met newline character). If the last character in a comment line is a \ the comment will be coninued in the next line.

sample:

// This is a single comment. The code below will be compiled.
void myFunction();

// This is a comment \
written in some lines. The code written below will be compiled.
void myFunction2();

void myFunction3(); // The code will be compiled, except this comment

Multi-line comment

A block of comment is consist of one to many comment at a single area. Start with /* and end with */. If you enclose code within it, the code would be part of comment. It won’t be compiled by compiler. remember to CLOSE the comment block you have start.

Sample:

/*
This is a comment
in a block
Expect it
*/
void myFunction();

/*
void myFunction2();
That function won't be compiled.
*/

void myFunction3(); /* this code would be compiled */

When and How to Comments

We have known the 2 comment types on C++. Now let’s inspect how can we use the comment? These are some nice style of commenting. I won’t force you to follow it.

  1. Write comment above or below a function to describe what it does and other characteristic (parameter / argument needed, return value, etc)
  2. If you write struct or class, write a member variable in a single line and give comment of what is it.
  3. a

There is a nice example about how we write a comment:

// This structure store value for computer register
struct Register {
int h; // This is the high bit
int l; // This is the low bit
};

/**
 * @author: Satria Ady Pradana
 *
 * Create a vector dynamically using heap allocation.
 * @pre
 *      V is not initialize
 *      size is defined and has value > 0
 *
 * @post
 *      V is created with size nodes
 *
 * @param
 *      V: a pointer
 *      size: size of list we want to create
 *
 * @return
 *      <none>
 *
 * @throw
 *     <none>
 */
void createVector(Pointer& V, int size);

A nice and sweet piece of code, right? 😀
The code is self explained with explanation for each stage. Each parameter is also documented.

Social media & sharing icons powered by UltimatelySocial