Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
3d7b7 session4 c++
1. Course Name- B Sc IT
Subject Name - C++
Semester - II
Neetu Gupta
1
2. Contents
• Function overloading
• Operator overloading
• Inheritance
• Different forms of inheritance
• Constructors and
• Destructors in inheritance
• Virtual base class
3. Contents
• Virtual base class
• Pointer to base class
• Dynamic polymorphism
• Virtual functions
• Type conversions
4. Function overloading
• In C we can have only one function with a
given name.
• But, in C++ we have a feature to declare
more than one function with the same
name as long as they have different
signatures i.e. parameters.
• The difference in parameters could be
either in number or type or both.
5. • Function overloading is the practice of declaring
the same function with different signatures.
• The same function name will be used with
different number of parameters and parameters
of different type. But overloading of functions
with different return types are not allowed.
• You overload a function name f by declaring
more than one function with the name f in the
same scope. The declarations of f must differ
from each other by the types and/or the number
of arguments in the argument list.
6. • For examples we can have following functions in a c++ program
void Add(int x, int y)
{
cout<<" Integer addition result: "<<(x+y);
}
void Add(double x, double y)
{
cout<< " Double addition result: "<<(x+y);
}
void Add(float x, float y)
{
cout<< " float addition result: "<<(x+y);
}
Three functions with same name i.e. Add(..) but differ in types
7. Calling an overloaded function
• When we call an overloaded function, the
correct function is selected by comparing
the argument list of the function call with
the parameter list of each of the
overloaded functions.
• The function i.e. actually called depends
upon the arguments we pass at the time of
function call statement.
• This is an example of static polymorphism
8. int main() {
Add (10,10);
Add (10.10d, 10.5d);
Add (10.10f, 10.5f);
}
• Add (10,10); calls the function void Add (int x,
int y)
• Add (10.10d, 10.5d); calls the function void
Add (double x, double y)
• Add (10.10f, 10.5f); calls the function void Add
(float x, float y)
9. • Remember function overloaded can not be
done on the basis of return type.
• For example following functions will give
error, as both the functions are same as
they only differ in return type:
void Add(int x, int y)
int Add(int x, int y)
10. Operator overloading
• C++ CVectororporates the option to use
standard operators to perform operations with
classes in addition to with fundamental types.
For example,
int a, b, c;
a = b + c;
• This is obviously valid code in C++, sCVectore
the different variables of the addition are all
fundamental types.
11. • But if we have a code like
• class Product {
string name;
float price;
};
Product prod1, prod2, prod3;
prod3 = prod1 + prod2; // Compilation error
• The above code will not work, as the compiler does
not on how to apply + on Product type variables i.e.
prod1 and prod2 here.
12. • Using C++ feature to overload operators,
we can design classes able to perform
operations using standard operators.
• Here is a list of all the operators that can
be overloaded:
+ - * / = < > += -= *= /=
<< >> <<= >>= == != <= >=
++ --
%&^!|~
&= ^= |= && || %= [] () , -> * ->
new delete new[] delete[]
13. • To overload an operator in order to use it with
classes we declare operator functions, which are
regular functions whose names are the operator
keyword followed by the operator sign that we
want to overload.
• The format is will be as:
type operator sign (parameters) {
/*...*/
}
14. • Example
#CVectorlude <iostream>
using namespace std;
class CVector {
public: int x, y;
CVector () {}; // default constructor
CVector (int,int); // constructor
CVector operator + (CVector); // + operator overloaded
};
CVector: CVector (int a, int b) {
x = a; y = b;
}
CVector CVector::operator+ (CVector param) {
CVector temp;
temp.x = x + param.x;
temp.y = y + param.y;
return (temp);
}
15. Here you have an example that overloads the
addition operator (+).
• We are going to create a class to store
bidimensional vectors
• X represents x-coordinate and y represents y-
coordinate value for a CVector.
• The addition of two bidimensional vectors is an
operation as simple as adding the two x
coordinates to obtain the resulting x coordinate
and adding the two y coordinates to obtain the
resulting y.
16. • Now see how can we use the class CVector as
int main () {
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
cout << c.x << "," << c.y;
return 0;
}
17. • Notice the below two methods
CVector (int, int); // function name CVector (constructor)
CVector operator+ (CVector); // function returns a CVector
• The function operator+ of class
CVector is the one that is in charge of
overloading the addition operator (+).
• This function of class CVector can be
called either implicitly using the operator,
or explicitly using the function name
18. c = a + b; // using the operator
c = a.operator+ (b); // using the function name
• Both these expressions are equivalent
and will call the +operator function defined
in class CVector.
• This way we can overload any binary
operator in c++ like - , /, % etc.
19. Unary operator overloading
We can overload unary operator using two ways
as
• with either a nonstatic member function that has
no parameters
return_type operator@()
• Or with a nonmember function that has one
parameter
return_type operator@(T)
Here,
@ could be any unary opeartor and T is a type.
return_type could be any type
20. Add the following function to class CVector
declared before
CVector CVector::operator! () {
CVector temp;
temp.x = !x;
temp.y = !y;
return (temp);
}
Here operator ! Is overloaded and define a
behavior for class CVector.
21. The above code can be use in main()
function as
int main() {
CVector ox(10,30);
CVector oy = !ox // function operator! Is called
}
22. • Overloading decrement (--) and
CVectorrement(++) operators is different
• SCVectore ++ and – have different
meanings for postfix and prefix we should
override both forms.
• For this we should add two set of functions
like
// Operator Function Definition for prefix
type operator ++ ();
type operator -- ();
23. // Operator Function Definition for postfix
type operator ++ (int);
type operator -- (int);
Here we make use of a dummy argument.
• As you can see in this case we use int as a
dummy argument for post-fix, when we redefine
the functions for the unary CVectorrement (++)
and decrement (--) overloaded operators.
• You must remember that int isn't an integer, but
just a dummy argument. You can see it as a
signal to the compiler to create the post-fix
notation of the operator.
24. • Two functions for ++ operator in class
CVector could be as below:
CVector operator ++ () {
// Operator Function Definition for prefix
return CVector (++x, ++y);
}
CVector operator ++ (int) {
// Operator Function Definition with dummy
//argument for postfix
return CVector (x++, y++);
}
25. • Similarly, Two functions for -- operator in
class CVector could be as below:
CVector operator -- () {
// Operator Function Definition for prefix
return CVector(--x, --y);
}
CVector operator -- (int) {
// Operator Function Definition with dummy
//argument for postfix
return CVector (x--, y--);
}
26. Remember
• In operator overloading always remember:
2. We can not change the precedence and
associatively of operators even if we overload
them in a class.
3. Few operators can not be overloaded like :
• scope resolution operator - ::
• sizeof operator
• Conditional operator (?:)
• class member access operators (.,.*)
27. Type conversion
• Type Conversion is the process of
converting one type into another.
• In other words converting an expression
of a given type into another is called type
casting or conversion
• There are two ways
• Automatic Conversion otherwise called as
Implicit Conversion
• Type casting otherwise called as Explicit
Conversion
28. Implicit Type Conversion
• This is automatic conversion, which is not
done using any operator or function.
• The value gets automatically converted to
the specific type in which it is assigned.
• Looking at the expression, the compiler
automatically converts an expression of
one type into another type
29. • For example
#include <iostream.h>
void main()
{
short x=6000;
int y;
y=x;
}
• In the above example the data type short namely
variable x is converted to int and is assigned to
the integer variable y.
30. • However, some type conversions are
inherently unsafe, and if the compiler can
detect that an unsafe conversion is being
implicitly requested, it will issue a warning.
• For example if we write the code as below
int nValue = 3.14156; // implicit conversion to integer value 3
Here the fractional part of the double value
3.14156 is dropped because int type can not
support fractional values.
31. • Because converting a double to an int
usually causes data loss (making it
unsafe), compilers such as Visual Studio
Express 2005 will typically issue a
warning.
• Few unsafe automatic conversions could
be
– assigning unsigned variables to signed
variables (and vice-versa),
– assigning large integers (eg. a 4-byte long) to
integer variables of a smaller size (eg. a 2-
byte short).
32. Explicit Conversion
• Explicit conversion can be done using type cast
operator and the general syntax for doing this is
datatype (expression);
• Here in the above datatype is the type which the
programmer wants the expression to gets
changed
• This is called c++ style casting
33. #include <iostream.h>
void main()
{
int a;
float b,c;
cout<< “Enter the value of a:”;
cin>>a;
cout<< “n Enter the value of b:”;
cin>>b;
c = float(a)+b;
cout<<”n The value of c is:”<<c;
}
Output is
Enter the value of a: 10
Enter the value of b: 12.5
The value of c is: 22.5
•
34. • In the above program a is declared as integer
and b and c are declared as float. In the type
conversion statement namely
c = float (a) + b;
• The variable a of type integer is converted into
float type and so the value 10 is converted as
10.0 and then is added with the float variable b
with value 12.5 giving a resultant float variable c
with value as 22.5
35. Inheritance
• Inheritance allows one data type to
acquire properties of other data types.
• Inheritance allows to create classes which are
derived from other classes, so that they
automatically include some of its "parent's"
members, plus its own.
• The original class is called the base class and
the new class created using base class is called
derived class.
36. • For example, we are going to suppose that we want to
declare a series of classes that describe polygons like
our CRectangle, or like CTriangle. They have certain
common properties, such as both can be described by
means of only two sides: height and base.
• This could be represented in the world of classes with a
class CPolygon from which we would derive the two
other ones: CRectangle and CTriangle.
• The class CPolygon would contain
members that are common for both types
of polygon. In our case: width and height.
And CRectangle and CTriangle would be
its derived classes, with specific features
that are different from one type of polygon
to the other.
37. NEED FOR INHERITANCE
• Capability to express the inheritance
relationship-This ensures the closeness with the
real world models.
• Reusability-The advantage of reusability are:
faster development time and easier
maintenance.
• Transitive nature of inheritance-If a class B
inherits properties of another class A then all
subclasses of B will automatically inherits the
properties of A. This property is called transitive
nature of inheritance.
38. Syntax
• In order to derive a class from another, we
use a colon (:) in the declaration of the
derived class using the following format:
class derived_class_name: public base_class_name
{ /*...*/
};
Here derived_class_name is the name of
the derived class and base_class_name is
the name of the class on which it is based.
39. // Example derived classes
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b) {
width=a; height=b;
}
};
class CRectangle: public CPolygon {
public: int area () {
return (width * height);
}
};
class CTriangle: public CPolygon {
public: int area () {
return (width * height / 2);
}
};
40. • We can use the above created classes as
int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
cout << rect.area() << “n”;
cout << trgl.area() << “n”;
return 0;
}
• The objects of the classes CRectangle and CTriangle each contain
members inherited from CPolygon. These are: width, height and
set_values().
• That’s is why we are using these members in main() method on the
objects of classes CRectangle and CTriangle.
41. • In CPolygon Class we used protected access specifier
• The protected access specifier is similar to private. Its
only difference occurs in fact with inheritance.
• When a class inherits from another one, the members of
the derived class can access the protected members
inherited from the base class, but not its private
members.
• Since we wanted width and height to be accessible from
members of the derived classes CRectangle and
CTriangle and not only by members of CPolygon, we
have used protected access instead of private.
42. • We can summarize the different access types according to who
can access them in the following way:
Access public protected Private
members of the yes yes yes
same class
members of the yes yes no
derived class
not members yes no no
• Here "not members" represent any access
from outside the class, such as from main(),
from another class or from a function.
43. protected inheritance
• So far we have code written like
class B : public A {}
This means that the class B is publicily derived
from B.
• We can specify protected derivation as well as
class B : protected A {}
• If we specify a more restrictive access level like
protected, all public members of the base class
are inherited as protected in the derived class.
44. • For example, if we write the code as
class CRectangle: protected CPolygon
{ ... }
• Then the function set_values() defined
public in CPolygon will become
protected in class CRectangle and we
can not write code like
CRectangle rect;
rect.set_values (4,5); // Error
45. private inheritance
• As we can have public and protected base class,
we can also have private base class.
• We can specify private derivation as well as
class B : private A {}
• If we specify a more restrictive access level like
private, all public and protected members of the
base class are inherited as private in the derived
class.
46. • For example, if we write the code as
class CRectangle: private CPolygon {
public: int area () {
return (width * height);
}
};
The above code will not compile, because
• We are inheriting CPolygon as private
base class, hence the protected members
width & height become private
47. Types of Inheritance
• Single Inheritance
- When a subclass
inherits only from
one base class,it is
known as single
inheritance.
class B: public A {
}
48. • Multiple Inheritance -
When a subclass
inherits from multiple
base classes, it is
known as multiple
inheritance.
class C: public A,
public B {
}
49. • Hierarchical Inheritance - When many
sub classes inherits from a single base
class,it is known as hierarchical
inheritance.
50. • Multilevel Inheritance - When a subclass
inherits from a class that itself inherits from
another class,it is known as multilevel
inheritance.
class B: public A {
}
class C : public B {
}
51. • Hybrid Inheritance - When a subclass
inherits from multiple base classes and all
of its base classes inherits from a single
base class,this form of inheritance is
known as hybrid inheritance.
52. Constructors & inheritance
• Suppose I have a class B derived from A as
class B : public A {
public:
B () {};
B (int i) {};
}
• If I create an object as
B b;
Then how the constructor of class A is called as we
are creating the object of class B only?
53. The rule is :
• Whenever we create an object of derived
class then constructor of base is called
automatically even if we do not call them
explicitly.
• If we are using multilevel inheritance then
the call to constructor is starting from the
first base class till the most derived class.
54. // Example
class A {
public:
A () {
cout << “In A’s Constructor n”;
}
}
class B : public A {
public:
B () {
cout << “In B’s Constructor n”;
}
}
class C : public B {
public:
C () {
cout << “In C’s Constructor n”;
}
}
55. main() {
C c;
}
Output will be
In A’s Constructor
In B’s Constructor
In C’s Constructor
Here we are creating an object of class C, so the
constructor of class A is called first, then B and
then C.
56. Destructor
• Like constructor, destructor of base is
called automatically when the object of
derived class s destroyed or deleted or
goes out of scope
• But the destructors are called in reverse
order of the constructor call.
• The destructor of derived is called first,
then of its base class and so on.
57. // Example
class A {
public:
A () {
cout << “In A’s Constructor n”;
}
~A () {
cout << “In A’s Destructor n”;
}
}
class B : public A {
public:
B () {
cout << “In B’s Constructor n”;
}
~B () {
cout << “In B’s Destructor n”;
}
}
class C : public B {
public:
C () {
cout << “In C’s Constructor n”;
}
~C () {
cout << “In C’s Destructor n”;
}
}
58. main() {
C c;
}
Output will be
In A’s Constructor
In B’s Constructor
In C’s Constructor
In C’s Destructor
In B’s Destructor
In A’s Destructor
59. Multiple inheritance and ambiguity
• We can inherit a class form more than one class and call
id multiple inheritance.
• Consider a inheritance situation as below:
A
member - i
B : public A C : public A
member – i of A member – i of A
D : public B,C
member – I of A via B
Member – I of A via C
60. • Here, the class D is derived form B and C. And
both B and C are derived from A.
• That means we have two copy of class A in class
D.
• When we create an object of class D, there are
two i of A, one instance via class B and other
instance of i via class C.
• If I write a code like:
D d;
d.i; // Error
Compiler is not able to resolve i in D as it has its
two instances.
61. Virtual base class
• Duplication of inherited members due to
these multiple paths can be avoided by
making the common base class as virtual
base class while declaring the direct or
intermediate base clases.
• Like we can declare the A as virtual base
class when we inherit the A in B and C
62. // Example
class A {
public:
int i;
}
class B : public virtual A {
………..
}
class C : public virtual A {
………..
}
class D : public C,D {
………..
}
63. Virtual functions
• Before understanding the virtual fucntions, lets
take a look at polymorphism.
• Pointers to base class
– One of the key features of derived classes is that a
pointer to a derived class is type-compatible with a
pointer to its base class. Polymorphism is the art of
taking advantage of this simple but powerful and
versatile feature, that brings Object Oriented
Methodologies to its full potential.
64. // pointers to base class
#include <iostream>
using namespace std;
class CPolygon {
protected: int width, height;
public:
void set_values (int a, int b) {
width=a; height=b;
}
};
class CRectangle: public CPolygon {
public: int area () {
return (width * height);
}
};
class CTriangle: public CPolygon {
public:
int area () {
return (width * height / 2);
}
};
65. int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
• In function main, we create two pointers that point to objects of class
CPolygon (ppoly1 and ppoly2). Then we assign references to rect
and trgl to these pointers, and because both are objects of classes
derived from CPolygon, both are valid assignment operations.
66. • The only limitation in using *ppoly1 and *ppoly2 instead
of rect and trgl is that both *ppoly1 and *ppoly2 are of
type CPolygon* and therefore we can only use these
pointers to refer to the members that CRectangle and
CTriangle inherit from CPolygon.
• For that reason when we call the area() members at the
end of the program we have had to use directly the
objects rect and trgl instead of the pointers *ppoly1 and
*ppoly2.
• In order to use area() with the pointers to class
CPolygon, this member should also have been declared
in the class CPolygon, and not only in its derived
classes, but the problem is that CRectangle and
CTriangle implement different versions of area, therefore
we cannot implement it in the base class. This is when
virtual members become handy.
67. Members declared as virtual
• A member of a class that can be redefined
in its derived classes is known as a virtual
member.
• In order to declare a member of a class as
virtual, we must precede its declaration
with the keyword virtual.
virtual returntype function_name (parameters)
68. // pointers to base class
#include <iostream>
using namespace std;
class CPolygon {
protected: int width, height;
public:
void set_values (int a, int b) {
width=a; height=b;
}
virtual int area () {
return (0);
}
};
class CRectangle: public CPolygon {
public: int area () {
return (width * height);
}
};
class CTriangle: public CPolygon {
public:
int area () {
return (width * height / 2);
}
};
69. • Now the three classes (CPolygon, CRectangle and CTriangle) have
all the same members: width, height, set_values() and area().
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
CPolygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
cout << ppoly3->area() << endl;
return 0;
}
70. • The member function area() has been declared as virtual
in the base class because it is later redefined in each
derived class.
• Now when we do the following
CRectangle rect;
CPolygon * ppoly1 = ▭
ppoly1->set_values (4,5);
cout << ppoly1->area() << endl;
Here the arear() method of appropriate class i.e. CRectangle is called because area() is
declared as virtual in base class.
• You can verify if you want that if you remove this virtual
keyword from the declaration of area() within CPolygon,
and then you run the program the result will be 0 for the
three polygons instead of 20, 10 and 0.
71. • That is because instead of calling the
corresponding area() function for each object
(CRectangle::area(), CTriangle::area() and
CPolygon::area(), respectively),
CPolygon::area() will be called in all cases since
the calls are via a pointer whose type is
CPolygon*.
• Rule is:
When a function is declared virtual in base class,
then the function call via base class pointer is
resolved at runtime and the function
called is of the class whose object it is.
72. • Therefore, what the virtual keyword does is to
allow a member of a derived class with the same
name as one in the base class to be
appropriately called from a pointer, and more
precisely when the type of the pointer is a
pointer to the base class but is pointing to an
object of the derived class, as in the above
example.
• A class that declares or inherits a virtual function
is called a polymorphic class.
• The resolving of function at runtime depending
upon the type of object is called dynamic
polymorphism.
73. Abstract base class
• Abstract base classes are something very similar to our
CPolygon class of our previous example.
• The only difference is that in our previous example we
have defined a valid area() function with a minimal
functionality for objects that were of class CPolygon (like
the object poly),
• whereas in an abstract base classes we could leave that
area() member function without implementation at all.
• This is done by appending =0 (equal to zero) to the
function declaration.
• An abstract base CPolygon class could look like this:
74. // abstract class CPolygon
class CPolygon {
protected: int width, height;
public:
void set_values (int a, int b)
{
width=a;
height=b;
}
virtual int area () =0;
};
• Notice how we appended =0 to virtual int area () instead of
specifying an implementation for the function. This type of
function is called a pure virtual function, and all classes that
contain at least one pure virtual function are abstract base
classes.
75. • Important : The main difference between an abstract base class and a
regular polymorphic class is that because in abstract base classes at least
one of its members lacks implementation we cannot create instances
(objects) of it.
• But a class that cannot instantiate objects is not totally useless. We can
create pointers to it and take advantage of all its polymorphic abilities.
Therefore a declaration like:
CPolygon poly;
would not be valid for the abstract base class we have just declared,
because tries to instantiate an object. Nevertheless, the following pointers
are valid:
CPolygon * ppoly1; CPolygon * ppoly2;
• This is so for as long as CPolygon includes a pure virtual function and
therefore it's an abstract base class. However, pointers to this abstract base
class can be used to point to objects of derived classes.
76. int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
return 0;
}
• If you review the program you will notice that we refer to
objects of different but related classes using a unique
type of pointer (CPolygon*). This can be tremendously
useful and called dynamic polymorphism.