106da session5 c++

Post on 02-Nov-2014

612 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

1

Course Name- B Sc IT

Subject Name - C++

Semester - II

Neetu Gupta

Contents

• Copy constructorFriend functions

• References data members

• Pointer data members

• Call by value

• Call by reference

Contents

• Function Template Definition• Function Template Instantiation• Class Template Definition• Class Template Instantiation• Non-type Parameters• Class Template Specialization• Class Template Members• Class Template Friends• Derived Class Templates

Copy Constructor

Copy constructor is• a constructor function with the same name as the class • used to make deep copy of objects.

• If a copy constructor is not defined in a class, the compiler itself defines one. This will ensure a shallow copy. If the class does not have pointer variables with dynamically allocated memory, then one need not worry about defining a copy constructor. It can be left to the compiler's discretion.

• But if the class has pointer variables and has some dynamic memory allocations, then it is a must to have a copy constructor.

There are 3 important places where a copy constructor is called.

• When an object is created from another object of the same type

A a1;

A a2 = a1;

• When an object is passed by value as a parameter to a function

• When an object is returned from a function

• For any class, the syntax for copy constructor will be like

class-name (const class-name &b)

1. Name of copy constructor is same as class name like any other constructor

2. The argument is of the class type itself.

3. The argument must be sent by reference

4. The argument must be sent as a constant value

class B    //With copy constructor{

          private:          char *name;

           public:         B()           {

           name = new char[20];           }           ~B()           {

           delete name[];           }

     //Copy constructor

         B (const B &b)           {

         name = new char[20];strcpy (name, b.name);          

}};

• Let us Imagine if you don't have a copy constructor for the class B.

• At the first place, if an object is created from some existing object, we cannot be sure that the memory is allocated.

• Also, if the memory is deleted in destructor, the delete operator might be called twice for the same memory location. This is a major risk.

• One happy thing is, if the class is not so complex this will come to the fore during development itself. But if the class is very complicated, then these kind of errors will be difficult to track.

• We can make use of this in a main() function as

main() {B b1;B b2 = b1;

}• Here, b2 is created from object b1 with the call of copy

constructor.• Hence the memory allocated to variable name will be

different for both the objects as we are doing so in copy constructor

• If we have not done so, then both the objects b1 and b2 would be pointing to same memory location which might lead to disasters in the program.

References

• C++ references allow you to create a second name for the a variable that you can use to read or modify the original data stored in that variable.

• This means that when you declare a reference and assign it a variable, it will allow you to treat the reference exactly as though it were the original variable for the purpose of accessing and modifying the value of the original variable--even if the second name (the reference) is located within a different scope. (important)

• This means, for instance, that if you make your function arguments references, and you will effectively have a way to change the original data passed into the function.

• It allows you to dramatically reduce the amount of copying that takes place behind the scenes, when we pass a argument by value in a function

Reference - Syntax

• Declaring a variable as a reference rather than a normal variable simply entails appending an ampersand to the type name, such as this "reference to an int"

int& foo = <variable-name>; • When a reference is created, you must tell it which variable

it will become an alias for or store the reference of.• After you create the reference foo, whenever you use the

variable, you can just treat it as though it were a regular integer variable. But when you create it, you must initialize it with another variable, whose address it will keep around behind the scenes to allow you to use it to modify that variable.

• In a way, this is similar to having a pointer that always points to the same thing.

• One key difference is that references do not require dereferencing in the same way that pointers do; you just treat them as normal variables.

• A second difference is that when you create a reference to a variable, you need not do anything special to get the memory address. The compiler figures this out for you

• A simple code could be asint x;

// foo is now a reference to x

int& foo = x;

// foo and x are same so

// if you change foo, it will set x to 56

foo = 56;

cout << x <<endl;

Here output will be

56

Functions taking References Parameters

• A parameter that we specify in function declaration can be a reference too.

• That means when we change the value of reference in the function, the value of actual argument will also get changed.

• This we call as pass-by-refrence. An important feature of C++.

• Here's a simple example of setting up a function to take an argument "by reference", implementing the swap function: void swap (int& first, int& second) {

int temp = first; first = second; second = temp;

}

• Here first and second are passed by reference. When we change the value of first and second then the changes will be reflected in the original arguments also.

int main () {int a = 2; int b = 3; swap( a, b ); // call to swap functionreturn 0;

}

• After the call of swap function a will be 3 and b will be 2.• Because a is passed to first and b is passed to second

in function swap. • Both are references. When we change first and second

in swap, a and b are also changed.

References as class members

• You can store members by reference if they are guaranteed to exist elsewhere.

• Reference member variables are used when the object they refer to exists outside of the scope of the class in question, and the same one is guaranteed to exist for the duration of the lifetime of your class' objects.

• A reference to the original is passed in as a parameter to the constructor and the reference member is initialized in the constructor's initialization list.

class A {}

class B {public:     

A& a;     // Reference to class type Aint x;

B(A& extr) :a(extr){ }

};

Here B is a class which hasone member variable a which is reference of type class Asecond member variable, a normal variable of int type.

void main() {     A ref;     B b(ref) ;     b.x=9; 

}Here we create an object ref of type A.• We send it to constructor of B, where it gets

initialized to a member of class B.• Since a is reference, the objects ref and a are

pointing to same object and not to two different objects.

Initializing reference members

• As we have already studied that a reference should always be initialized with a variable when it is declared.

• Hence, if we have a member variable declared as reference it must be initialized in the initialization list always otherwise compiler will give an error.

//class B {

public:     A& a;     // Reference to class type Aint x;

B(A& extr) :a(extr) // initialized in initialization list{

a = extr; // compiler Error;}

};

• If we try to assign a value to a reference in the constructor it will an error, as shown above.

• Because giving reference a value in constructor is assignment not initialization.

• It should always be done in the initialization list.

Pointers as data members

• Like normal variables, we can always have data members which are pointers to a data type.

class A {

int* iptr;

}• Here, the iptr is a pointer to int and not a simple

int type variable.• We should take special care when we have

pointer data members

• A pointer data member should be properly allocated and deallocated memory in the constructor and destructor of the class.

• Every class that has a pointer data member should include the following member functions: – a destructor, – a copy constructor, – operator= (assignment)

• Lets take an exampleclass Test    //With copy constructor{

          private:          char *name;

           public:         Test()           {

           name = new char[20];           }           ~ Test()           {

           delete name[];           }     

};

• Class test, has a data member name which is a pointer to char type.

• We must be careful to alocate memory in constructor for this using new operator.

• Similarly when the object is destroyed, destructor will be called. We should be careful to deallocate the memory that is allocated in constructor using delete operator.

Call by value vs. call by reference

• When we write a function likef ( int x ) {

cout >> “ value of X in f() before change : “ >> x;x =3;cout >> “ value of X in f() before change : “ >> x;

}Here x is passed by value that means if we change

the value of x in f(), there will be no effect on the value of argument that is sent at the time of f() call.

This is called as pass-by-value

• If we call function f() in main asmain() {

int i =10;cout >> “ value of I before calling f() : “ >> I;f(i);cout >> “ value of I after calling f() : “ >> I;

}

Output will be :value of I before calling f() : 10value of X in f() before change : 10value of X in f() before change : 3value of I after calling f() : 10

• The value of i is set to 10 that is what is printed.• When we pass I to f(), its value is set to X so X is

10.• Later we change X to 3, that is what is printed.• The control comes back to main after calling f(),

the I is still 10.• Though we changed the value of parameter X in

f(), but the changes are not reflected in i.• This is because X is passed by value.

• Pass by referenceWhen we write a function like

f ( int& x ) {cout >> “ value of X in f() before change : “ >> x;

x =3;cout >> “ value of X in f() before change : “ >> x;

}• Here x is passed by reference and not by value

that means if we change the value of x in f(), there will be change in the value of argument that is sent at the time of f() call. This is called as pass-by-reference

• If we call function f() in main asmain() {

int i =10;cout >> “ value of I before calling f() : “ >> I;f(i);cout >> “ value of I after calling f() : “ >> I;

}

Output will be :value of I before calling f() : 10value of X in f() before change : 10value of X in f() before change : 3value of I after calling f() : 3

• The value of i is set to 10 that is what is printed.• When we pass I to f(), its value is set to X so X is

10.• Later we change X to 3, that is what is printed.• The control comes back to main after calling f(),

the I is 3 now.• We changed the value of parameter X in f(), the

changes are now reflected in i.• This is because X is passed by reference.

Templates

• Templates are used to write down generaic code.

• When we need to write a common code for different data type basic or class type we can do so with the help of templates.

• In c++, we will study 2 types1. Function templates

2. class templates

Function Templates

• Function templates are special functions that can operate with generic types.

• This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type.

• In C++ this can be achieved using template parameters.

Template parameter

• A template parameter is a special kind of parameter that can be used to pass a type as argument.

• As regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

• These function templates can use these parameters as if they were any other regular type to write a code for generic data type or class.

Function template syntax

• The format for declaring function templates with type parameters is:

template <class identifier> function_declaration;template <typename identifier> function_declaration;

• The only difference between both prototypes is the use of either the keyword class or the keyword typename.

• Its use is indistinct, since both expressions have exactly the same meaning and behave exactly the same way.

• For example, to create a template function that returns the greater one of two objects we could use:

template <class myType> myType GetMax (myType a, myType b) {

return (a>b?a:b); }

• Here we have created a template function with myType as its template parameter.

• This template parameter represents a type that has not yet been specified, but that can be used in the template function as if it were a regular type.

• As you can see, the function template GetMax returns the greater of two parameters of this still-undefined type.

Function template - Use

• To use this function template we use the following format for the function call:

function_name <type> (parameters);

• For example, to call GetMax to compare two integer values of type int we can write:

int x,y; GetMax <int> (x,y);

• When the compiler encounters this call to a template function like,

GetMax <int> (x,y);

it uses the template to automatically generate a function replacing each appearance of myType by the type passed as the actual template parameter (int in this case) and then calls it.

• This process is automatically performed by the compiler and is invisible to the programmer.

// function template #include <iostream> using namespace std; template <class T> T GetMax (T a, T b) {

T result; result = (a>b)? a : b; return (result);

}

int main () { int i=5, j=6, k; long l=10, m=5, n; k=GetMax<int>(i,j); // create a function for int typen=GetMax<long>(l,m); // create a function for long typecout << k << endl; cout << n << endl; return 0;

}

Output is6 10

• In this case, we have used T as the template parameter name instead of myType because it is shorter and in fact is a very common template parameter name.

• In the example above we used the function template GetMax() twice.

• The first time with arguments of type int and the second one with arguments of type long.

• The compiler has instantiated and then called each time the appropriate version of the function.

• As you can see, the type T is used within the GetMax() template function even to declare new objects of that type:

  T result;

• Therefore, result will be an object of the same type as the parameters a and b when the function template is instantiated with a specific type.

• Our template function includes only one template parameter (class T) and the function template itself accepts two parameters, both of this T type.

• We cannot call our function template with two objects of different types as arguments:

int i; long l; k = GetMax (i,l);

• This would not be correct, since our GetMax function template expects two arguments of the same type, and in this call to it we use objects of two different types.

More than one type parameter

• We can also define function templates that accept more than one type parameter, simply by specifying more template parameters between the angle brackets.

• For example:template <class T, class U> T GetMin (T a, U b) {

return (a<b ? a :b); }

In this case, our function template GetMin() accepts two parameters of different types and returns an object of the same type as the first parameter (T) that is passed.

• For example, after that declaration we could call GetMin() with:

int I, j;

long l; i = GetMin<int, long> (j, l);

or simply:i = GetMin (j, l);

Here even though j and l have different types, since the compiler can determine the appropriate instantiation anyway.

Class Template• We also have the possibility to write class templates, so that a class

can have members that use template parameters as types.

• For exampletemplate <class T> class mypair {

T values [2]; public:

mypair (T first, T second) { values[0]=first;

values[1]=second; }

};

• We can define a class Template as

For exampletemplate <class T> class mypair {

T values [2]; public:

mypair (T first, T second) { values[0]=first;

values[1]=second; }

};

• The class that we have just defined serves to store two elements of any valid type.

Class Template definition

• For example, if we wanted to declare an object of this class to store two integer values of type int with the values 115 and 36 we would write:

  mypair<int> myobject (115, 36);

• The same class would also be used to create an object to store any other type:

  mypair<double> myfloats (3.0, 2.18);

• The only member function in the previous class template has been defined inline within the class declaration itself.

• In case that we define a function member outside the declaration of the class template, we must always precede that definition with the template <...> prefix as:

template <class T> T mypair<T>::getmax ()

// class templates #include <iostream> using namespace std; template <class T> class mypair {

private:T a, b;

public: mypair (T first, T second) {

a=first; b=second;} T getmax ();

};

template <class T> T mypair<T>::getmax () {

T retval; retval = a>b? a : b; return retval;

}

• In the example, mypair is the class that stores two template type variables.

• It also has a function getMax(), that find out the maximum of two numbers the object of class stores.

• The compiler will generate the complete code of the class for each type, when we declare an object of the class myPair specifying a type of T.

• For exampleint main () {

mypair <int> myobject (100, 75);cout << myobject.getmax(); return 0;

}

• In this example, a complete class is created with T as int, because we are using mypair <int>. This we can call instantiation of class template.

Class Template Instantiation

Template specialization

• At times we want to define a different implementation for a template when a specific type is passed as template parameter

• We can always declare a specialization of that template for that particular data type as the need be.

• This is the syntax used in the class template specialization:

template <> class mycontainer <char> {

... };

• Notice that we precede the class template name with an empty template<> parameter list. This is to explicitly declare it as a template specialization.

• For example, let's suppose that we have a very simple class called mycontainer that can have the members as1. one element of any type and 2. it has just one member function called increase,

which increases its value. 3. But we find that when it stores an element of type

char it would be more convenient to have a completely different implementation with a function member uppercase,

4. so we decide to declare a class template specialization for type char only.

// template specialization #include <iostream> using namespace std;

// class template: template <class T> class mycontainer {

T element; public:

mycontainer (T arg) {element=arg;

}

T increase () {return ++element;

} };

// class template specialization for char type will be as: template <> class mycontainer <char> {

char element; public:

mycontainer (char arg) {element=arg;

} char uppercase () {

if ((element>='a')&&(element<='z')) element+='A'-'a';

return element; }

};

Carefully see the code usedtemplate <>

• This is to explicitly declare it as a template specialization.

class mycontainer <char> { ... };

• Here <char> is the specialization parameter after the class template name. This specialization parameter itself identifies the type for which we are going to declare a template class specialization i.e. char.

• Notice the differences between the generic class template and the specialization:

template <class T> class mycontainer { ... }; template <> class mycontainer <char> { ... };

Here first line is the generic template,second one is the template specialization.

Remember• When we declare specializations for a template class, we

must also define all its members, even those exactly equal to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.

•Besides the template arguments that are preceded by the class or typename keywords , which represent types, templates can also have regular typed parameters, similar to those found in functions.Like we can a particular type specified like int, float, or any class-type as well as

template <class T, int N> Here T is template type where as second parameter is fixed i.e. int here.

60

Non-type parameters for templates

// sequence template // this class template that is used to contain sequences of elements

#include <iostream> using namespace std;

template <class T, int N> class mysequence {

T memblock [N]; public:

void setmember (int x, T value); T getmember (int x);

};

template <class T, int N> void mysequence<T,N>::setmember (int x, T value) {

memblock[x]=value; }

template <class T, int N> T mysequence<T,N>::getmember (int x) {

return memblock[x]; }

61

•In the class mysequence we have two arguments for template;

first is template typename that will vary when we create an object of this class

second is specific i.e. int and when we create an object we will use this as

mysequence <double, 5> mydoubles;

double replaces T5 is the value for parameter N

62

int main () { mysequence <int,5> myints; mysequence <double,5> myfloats;

myints.setmember (0,100); myfloats.setmember (3,3.1416); cout << myints.getmember(0) << '\n'; cout << myfloats.getmember(3) << '\n'; return 0;

}

63

It is also possible to set default values or types for class template parameters.

For example, if the previous class template definition had been:

template <class T=char, int N=10> class mysequence {..};

We could create objects using the default template parameters by declaring:

  mysequence<> myseq;

This would be same as

mysequence<char,10> myseq

64

Default values for class template parameters

• It is also possible to set default values or types for class template parameters.

For example, if the previous class template definition had been:

template <class T=char, int N=10> class mysequence {..};

We could create objects using the default template parameters by declaring:

  mysequence<> myseq;

This would be same as

mysequence<char,10> myseq

Friends functions

• In principle, private and protected members of a class cannot be accessed from outside the same class in which they are declared.

• However, this rule does not affect friends.

• Friends are functions or classes declared with the friend keyword.

• we can declare an external function as friend of a class

• This allows this function to have access to the private and protected members of this class.

• For this 1. We should declare a prototype of this

external function within the class,

2. and preceding it with the keyword friend

• Suppose we want to declare an external function in our program, that create a copy of CRectangle class.

• This function should be likeCRectangle duplicate (CRectangle rectparam) {

CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2;return (rectres);

}• But if we define this function outside class, we can not access width

and height members of class CRectangle here as they are protected or private.

• For this we declare this function as friend to class CRectangle

// friend functions #include <iostream> using namespace std; class CRectangle {

int width, height; public:

void set_values (int, int); int area () {

return (width * height);} friend CRectangle duplicate (CRectangle); // friend function declaration in class

};

void CRectangle::set_values (int a, int b) { width = a; height = b;

}

CRectangle duplicate (CRectangle rectparam) { CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2; return (rectres);

}

• It can be used as

int main () { CRectangle rect, rectb; rect.set_values (2,3); rectb = duplicate (rect); cout << rectb.area(); return 0;

}

• The duplicate function is a friend of CRectangle. From within that function we have been able to access the members width and height of different objects of type CRectangle, which are private members.

• Notice that neither in the declaration of duplicate() nor in its later use in main() have we considered duplicate a member of class CRectangle.

Friend classes

• As we have the possibility to define a friend function, we can also define a class as friend of another class

• We can do so by granting that first class access to the protected and private members of the second class.

• This can be done by declaring first class as a friend of other class.

Friend class - syntax

• We can do this as

class A {

public:

friend class B;

}

• Here class B is friend of class A that means class B can access the all private and protected members of class A.

Example:• Suppose we want to have declared CRectangle

as a friend of CSquare so that CRectangle member functions could have access to the protected and private members of CSquare, more concretely to CSquare::side, which describes the side width of the square.

• This is necessary because within the declaration of CRectangle we want to add a function convert() that will change an object of type CSquare to CRectangle.

// friend class #include <iostream> using namespace std; class CSquare; class CRectangle {

private : int width, height;

public: int area () {return (width * height);} void convert (CSquare a);

};

class CSquare { private:

int side; public:

void set_side (int a) {side=a;} friend class CRectangle; // declares CRectangle as the friend class of

CSquare};

void CRectangle::convert (CSquare a) { width = a.side; // accessing private member of CSquare classheight = a.side;

}

• Now we can easily covert a CSquare class into CRectangle as

int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); // conversioncout << rect.area(); return 0;

}Output is:

16

Thank You

76

top related