Tuesday, May 4, 2010

templates

Templates: This feature of C++ is comparable to generics of Java. Though both of them are implemented very differently internally serve similar purpose to an extent. Templates helps in writing code at one place for multiple data types. As word indicates we specify template for a class or function to work on multiple data types. Compiler generates version for the data type using which call is made.

Example:
// Template method example
template
T sum(T a, T b) {
return a + b;
}

...
int result = sum(10, 20);
float res = sum(10.2, 20.1);

// Error: templates follow strict type checking
// float result = sum(10, 20.2);

In above example compiler will generate int and float version of the method.

Similarly we write template for the class.
Example
// Template class example
template
class Sample {
private:
T data;
public:
T getData() {
return data;
}
void setData(T d);
};

// Notice how the method is defined outside class
template
void Sample::setData(T d) {
data = d;
}

main() {
Sample sample;
sample.getData();
}

Template argument can take default values. Default values become compile time constants.

template
class Sample {
private:
T container[MAX];
};


From C to C++ - misc...

Miscellaneous points:

Function declaration:
In C++ function must be declared before it is used. Function declaration/prototype should provide return type, number and type of arguments it take.

Example:
void display(char *);
void display(char *name); // better

Old C Structure: C++ has construct called structure which same as class except that in structure default access is public while in classes default access is private

Union and Enum: C++ has constructs called union and enum.
Example:


enum Gender { MALE, FEMALE };

union Data {
char name[20];
int age;
Gender sex;
};

Data d;
Gender sex;

Union is similar to structure except that it uses same memory location for all three items. i.e. size of the union is 20 (max of 3 items) while size of the same struct would be 28.

In C++ there is also a concept of anonymous union and enums

union {
char name[20];
int age;
};

enum { MALE, FEMALE };


name[0] = 'A';
age = 20;
int sex = MALE;

void *: We can assign any pointer to void* but cannot assign void* to another pointer, explicit conversion (type casting) is needed in 2nd operation.

Example:
void *vpointer;
chr *name;

name = (char *) vpointer; // conversion is needed
vpointer = name; // conversion not needed

bool: C++ has datatype similar to boolean in Java except that any integer can be converted to bool and vice-versa. integer != 0 is true while integer value 0 is interpreted as false

Example:
int num = 10;
bool isnum = true;

isnum = num;
cout <<>
num = isnum;
cout <<>

typedef: Typedef provides alias for an existing type. It doesn't create new type of its own.

typedef MYTYPE char*;
void display(char *);
void display(MYTYPE); // same as above hence throws an error

inline function: There are two kinds of inline functions.
  • Function explicitly declared as inline
Example:
inline void display() { // It's just a request to the compiler. Compiler can choose to ignore the request.
cout << "hello";
}

  • Function defined in the class body. Its more of C++ lingo than actual inline function as described above.

class sample {
public:
void display() {
cout << "hello"; // In lingo it is called defined inline.
}
};

Casting: Other than implicit data conversion C++ supports 4 different kind of type casting.
  • dynamic_cast: Checks at runtime if object is of given type. it returns address if object is of given type else returns 0
Sample *sample;
Base *base;
if (sample = dynamic_cast
(base)) {
...
}
  • static_cast: Used to convert between compatible types.
    • castless conversion i.e. int to long etc.
int rate = 10;
long base = static_cast(rate);
    • conversion from void*
Base* base = static_cast<>(vptr);

    • narrowing conversion i.e. from float/long to int
long rate = 10.6;
int base = static_cast(rate);

    • from derived to base and vice versa.
Base* base = static_cast (&derived);
  • const_cast: Used to convert const to non-const i.e.
const int a = 10;
int *p = const_cast(&a);

  • reinterpret_cast: Least safe of them all. Used to convert pointer to integers and vice versa.
int num = 65000;
int *address = reinterpret_cast(num);


RTTI (RunTime Type Identification): Other than dynamic_cast C++ provides another way to know the type of the object in runtime.
Example:
int num = 10;
typeid(num).name();

From C to C++

const: Const is C++ version of final in Java. Const can be used at many places.
  • const variable
    • any variable be it global, local, or in class if declared const becomes un-modifiable
  • const member function
    • Method in a class declared as const cannot modify variable inside
    • Declaration: void display() const; // remember const is after the brackets
    • Definition: void classname::display() const { ... }
  • const object
    • Can't modify any of the data member except ones declared as mutable
    • Can call only const methods as they are the only ones guaranteed not to modify object state

Use it often. Makes code more safer.

Example:

const char* name = "shreyas"; // string is constant pointer is not (read R to L)
name = "dhara";
*name = 'S' // Error

char const *location = "hyderabad"; // same as above

char * const weather = "hot"; // pointer is constant string is not
weather = "cool"; // Error
*weather = 'H';

const char * const weather = "hot"; // Both pointer and string it points to are constant
weather = "cool"; // Error
*weather = 'H'; // Error


Coonst and reference: If variable is declared const it's reference must also be declare const. Vice versa is not true
Example:
const int i = 10;
const int &ref = i;
int &err = i; // gives error

int j = 20;
const int &cref = j;

Note. if you return const string like "hello" your method declaration should be

const char* getname() {
return "hello";
}


mutable: Mutable let's you modify the member of const object. By definition const object is non-modifiable and you can only call const methods on them. By setting it mutable you can modify member variable of const object.
Example:
class Sample {
private:
mutable int num;

public:
// It is ironic that we have to declare method as const
// that actually modifies the variable
void setNum(int n) const {
num = n;
}
};

...
Sample s;
s.setNum(20);

namespace: It is similar to java's package.
Example:
namespace sample {

// Nested namespace is allowed
namespace nested {

}

class Base {
};

void display();
} // namespace sample

// Definition outside namespace
void sample::display() {
cout << "outside namespace";
}

// We can give alternate name to a namespace
namespace very_very_long_namespace {

class Trial {
};

}

namespace vvln = very_very_long_namespace;

int main() {
sample::Base base;

// Alternate way
using namespace sample;
Base base;

// Error cannot have namespace at global level
// namespce local {
// }
}

From C to C++

reference: In C you can pass/return values to a function in 2 ways. 1. By value 2. By address (Using pointer). C++ introduces third way to return/pass values. It is called by reference. Reference is similar to a pointer but has following properties.
  • One variable can have multiple references
  • But a reference can refer to only one variable in its life time.
  • Reference needs to be initialized (declared and defined in same line).
    • You can't do int i; int &ref; ref = i;
    • int i; int &ref = i;
  • Reference are so tightly coupled that any change in one reflect in change in all others

Example:
int i = 10;
int &ref = i;

void funct_r(int &ref);
void funct_v(int val);
void funct_a(int *add);
...
...
main() {
int i = 10;
funct_r(i); // call by reference
funct_v(i); // call by value
funct_a(&i);
}

reference are more readable than pointers while for most part they work like pointers. Btw, it is also possible to create reference to a pointer.

e.g.
char *name = "India";
char *& ref = name; // Read from right to left... it says reference to a char *

Points to remember:
  • We cannot have a array of references
  • Never return local variable by reference

OOP in C++ - contd...


static:
Static variable has default value 0. Static variable in the class needs to be defined out side class. Class can have static method as in Java which if defined out side will not have static word with it.
Method cannot be a both static and const.

Example:
class Sample {
private:
static int index;
public:
static void display();
};

int Sample::index = 10;

void Sample::display() { // Note no static here
cout <<>
}

Error prone features:
Features that C++ provides but we are better off without them as they can lead to many unwanted side-effects. If we use them it can lead to un-intentional calls being made and can lead to errors which can be very difficult to trace. Following are the list of error prone features. (We are not going in details about it).

  • Operator overloading
  • Default arguments in functions
  • Copy constructor
  • = operator
  • Exception handling

If you want to read further refer to style guide


explicit: C++ compiler is quite pro-active in trying to determine programmer's intention. It tries to find the closest match for performing an operation. If it doesn't fine one it will use nearest one.
Example:
class Sample {
public:
Sample(int i) {
num = i;
}

private:
int num;
};

...

Sample s = 10;
s = 20;

In above code, compiler will first look for overloaded
= operator. On failure to find that it will look for one argument constructor with int. This is called implicit conversion.
If we want to make sure that particular constructor should be invoked explicitly used then add explict before contructor.

OOP in C++ - contd...

virtual functions: Virtual functions are C++ way to achieve run-time polymorphism. Unlike Java, C++ provides calls derived class's version only if base class's method is declared virtual. If method is not declared virtual in base class C++ will always call base class's version irrespective of the object being pointed to. C++ doesn't have abstract key work but supports the abstract class concept. Function is called pure virtual function that doesn't have body.
Example
class Base {
public:
// Pure virtual function.
virtual void display() = 0;
};

Class with at least one pure virtual function is called abstract class. (Abstract class whose object can't be created.) If derived class doesn't implement pure virtual function method of base class it also remains abstract. C++ achieves runtime polymorphism by creating virtual table for each class (and also all it's sub classes) that has virtual method. Each object of that class contains a pointer called virtual pointer that points to the virtual table. Virtual table contains location of the methods. It stores location of derived class version for virtual methods and location of base class version for non-virtual methods.

Example:
class Base {
public:
virtual void display() {
cout << "In base";
}

void show() {
cout << "In base show";
}

virtual ~Base() {}
};

class Derived : public Base {
public:
void display() {
cout << "In derived" <<>
}
};

int main() {
Base *base = new Derived;
base->display();
base->show();
delete base;
}

Output:
In derived
In base show

Execution sequence: When base.display() is called. Internally it asks *(vptr->display)(). In virtual function compiler instead of using this it uses vptr. vptr points to the class's virtual table, in this case derived class's virtual table. When virtual table is constructed address of base class version is inserted for all non-virtual methods. That's why late binding works only for virtual methods and only with pointers.

virtual destructor: As with normal virtual function we want destructor of class being pointed to be called rather than base class's destructor when we delete the object. If destructor is not declared virtual compiler will call base class's destructor which will result in invalid deletion of the object. Hence every time we have virtual method in a class, class's destructor should also be declared virtual.

virtual base class: Not seen usage of this feature but for the sake of completeness. C++ has another feature called virtual base class inheritance. In one particular case of multiple inheritance there can be a conflict in accessing data.
Example:
class Base {
protected:
int data;
};

class Derived1 : public Base {
};

class Derived2 : public Base {
};

class Derived3 : public Derived1, public Derived2 {
public:
void display() {
cout <<>
}
};

See class Derived3. In above case compiler will find conflict in deciding which derived class's data it should refer to. Conflict can resolved by using Derived2::data or Derived3::data. There is one more way. If we want both derived classes to share base class's data we can inherit them virtually.

class Derived1 : virtual public Base {
};

class Derived2 : virtual public Base {
};

In this case Derived1 and Derived2 will share the same data.

OOP in C++ - contd...


inheritance: C++ supports multiple inheritance and multiple level of inheritance. C++ also supports multiple way to inherit a class. Let's start with multiple inheritance. C++ let's derived class inherit more than one class.

  • Constructors are called in the order in which the classes are declared in the derived class declaration not in the order in which they are mentioned in costructor

Example:
class Base1 {
private:
int num;

public:
public Base1(int n) { num = n; }
};

class Base2 {
};

class Derived : public Base, public Base1 {
private:
int num1;
public:
// Base's constructor will be called first rather than Base1
// It will follow class declaration above
Derived(int n1, int n2) : Base1(n2), Base() {
num1 = n1;
}
};

  • In case if both the base classes contains same method or variable, conflict can be resolved using resolution operator and class name.

Example:
class Base1 {
public:
void display();
}

class Base2 {
public:
void display();
}

class Derived : public Base1, public Base2 {
}

...

Derived d;
// Conflict resolution
d.Base1::display();

Type of inheritance: C++ let's class to be inherited publicly, protectedly or privately. Default access specifier/inheritance is private.

  • In public inheritance public and protected methods of base class remains as public and protected methods of derived class
class Base {
public:
void display();
protected:
void inheritable();
};

class Derived : public Base {
}

class DoubleDerived : public Derived {
// inheritable is visible here
}

...
DoubleDerived dd;
dd.display();


  • In private inheritance public and protected methods of base class become private methods of derived class
class Derived : private Base {
}

class DoubleDerived : public Derived {
// nheritable is NOT visible here
}
...
DoubleDerived dd;
dd.display(); // Error, not accessible


  • Similarly, in protected inheritance public and protected methods of base class becomes protected methods of derived class
class Derived : private Base {
}

class DoubleDerived : public Derived {
// nheritable is visible here
}
...
DoubleDerived dd;
dd.display(); // Error, not accessible

Selective private inheritance: It is possible to inherit class privately yet have public access to specific base method.
Example:
class Base {
public:
void display();
};

class Derived : private Base {
public:
// Note that we are specifying only function name parentheses are missing
Base::display;
};

Order of calling of constructors and destructors: In case of In case of inheritance base class's constructor is called first and then the constructor of the derived class is called. It's because when we are in derived class we should be sure that base class's part is already constructed. Similarly when we are in derived class's destructor we can safely assume that base class's part of the object is still there. To justify that derived class's destructor is called prior to base class's destructor.

Note: zero argument constructor, destructor, copy constructor and assignment operators are not inherited.