WordPress Websites for Engineers: Elevate Your Brand
106da session5 c++
1. Course Name- B Sc IT
Subject Name - C++
Semester - II
Neetu Gupta
1
2. Contents
• Copy constructorFriend functions
• References data members
• Pointer data members
• Call by value
• Call by reference
3. 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
4. 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.
5. 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
6. • For any class, the syntax for copy constructor
will be like
class-name (const class-name &b)
5. Name of copy constructor is same as class
name like any other constructor
6. The argument is of the class type itself.
7. The argument must be sent by reference
8. The argument must be sent as a constant
value
7. 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);
}
};
8. • 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.
9. • 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.
10. 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)
11. • 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
12. 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.
13. • 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
14. • A simple code could be as
int 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
15. 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++.
16. • 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.
17. int main () {
int a = 2;
int b = 3;
swap( a, b ); // call to swap function
return 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.
18. 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.
19. class A {
}
class B {
public:
A& a; // Reference to class type A
int x;
B(A& extr)
:a(extr)
{
}
};
Here B is a class which has
one member variable a which is reference of type class A
second member variable, a normal variable of int type.
20. 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.
21. 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.
22. //
class B {
public:
A& a; // Reference to class type A
int 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.
23. 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
24. • 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)
25. • Lets take an example
class Test //With copy constructor
{
private:
char *name;
public:
Test()
{
name = new char[20];
}
~ Test()
{
delete name[];
}
};
26. • 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.
27. Call by value vs. call by reference
• When 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 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
28. • If we call function f() in main as
main() {
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() : 10
value of X in f() before change : 10
value of X in f() before change : 3
value of I after calling f() : 10
29. • 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.
30. • Pass by reference
When 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
31. • If we call function f() in main as
main() {
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() : 10
value of X in f() before change : 10
value of X in f() before change : 3
value of I after calling f() : 3
32. • 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.
33. 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 types
1. Function templates
2. class templates
34. 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.
35. 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.
36. 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.
37. • 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.
38. 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);
39. • 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.
40. // 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 type
n=GetMax<long>(l,m); // create a function for long type
cout << k << endl;
cout << n << endl;
return 0;
}
Output is
6
10
41. • 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.
42. • 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.
43. • 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.
44. 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.
45. • 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.
46. 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 example
template <class T>
class mypair {
T values [2];
public:
mypair (T first, T second) {
values[0]=first;
values[1]=second;
}
};
47. Class Template definition
• We can define a class Template as
For example
template <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.
48. • 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);
49. • 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 ()
50. // 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;
}
51. • 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.
52. Class Template Instantiation
• 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 example
int 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.
53. 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.
54. • 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.
55. • For example, let's suppose that we have a very
simple class called mycontainer that can have
the members as
• one element of any type and
• it has just one member function called increase,
which increases its value.
• 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,
• so we decide to declare a class template
specialization for type char only.
56. // 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;
}
};
57. // 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;
}
};
58. Carefully see the code used
template <>
• 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.
59. • 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.
60. Non-type parameters for
templates
•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
61. // 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
62. •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 T
5 is the value for parameter N
62
64. 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
65. 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
66. 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.
67. • 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
• We should declare a prototype of this
external function within the class,
• and preceding it with the keyword friend
68. • Suppose we want to declare an external
function in our program, that create a copy
of CRectangle class.
• This function should be like
CRectangle 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
69. // 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);
}
70. • 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.
71. 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.
72. 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.
73. 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.
74. // 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 class
height = a.side;
}
75. • Now we can easily covert a CSquare class into
CRectangle as
int main () {
CSquare sqr;
CRectangle rect;
sqr.set_side(4);
rect.convert(sqr); // conversion
cout << rect.area();
return 0;
}
Output is:
16