Oops
Oops
Virtual Functions
12. Encapsulation
13. Data abservation
1. OOPS DESIGN PRINCIPLE
Dry
Kiss
Yagni
2. COHESION & COUPLING
3. CQS
4. SOLID
OPPS DESIGN PATTERN
1. Factory method design pattern:-
2. SINGLETON DESIGN PATTERN:-
3. Builder design pattern
4. Observer design pattern
5. Abstract factory design
Class :- Blueprint
Design/ type :- 1. State / property / field / data function
2. behavior / function / data function.
Ex. Humans :- 1. 2 hand
2. 2 leg
3. 2 eyes
Behavior :- walk, speak, eat.
Architect give blueprint is class, wing the blueprint, we make the house is object.
Object takes memory / space, class doesn’t, object is an implementation / real entity /
instance of class.
Class is a logical component.
object takes memory from heap.
1. class Human {
2. public:
3. //properties
4. int age;
5. int weight;
6.
7. //behavior
8. void sleep()
9. {
10. cout<<“He is sleeping”<<end;
11. }
12.
13. void eat()
14. {
15. cout<<“He is eating”<<endl;
16. }
17. };
18.
19.
20. int main()
21. {
22. Human chitti;
23. chitti.age = 25;
24. chitti.weight = 40;
25. chitti.sleep();
26. chitti.eat();
27 }
Access modifiers in C++ :-
One of the main features of oops is data hiding.
Data Hiding :- Data Hiding refers to restricting access to data members of a class. This
is to prevent other functions and classes from tampering with the class data.
the access modifiers of C++ allows up to determine which class members are accessible
to other classes and functions, and which are not.
There are 3 types of access modifiers available in C++,
1. Public
2. Private
3. Protected
By default, the access modifier of the members will be provide.
1. Public :- The public keyword is used to create public members (data and functions).
The public members are accessible from only part of the program.
The public members can be accessed from anywhere in the wing direct memory access
operator (.) with the object of that class.
1. class Rectangle{
2.
3. public:
4. int Length, Breadth;
5.
6. Rectangle()
7. {
8. Length=5;
9. Breadth=5;
10. }
11.
12.
13.
14. void Display()
15. {
16. cout<<“\n Length “<<Length;
17. cout<< “\n Breadth “<<Breadth;
18. }
19. };
20.
21. int main()
22. { Rectangle R;
23. cout<<R. Length<<“ ”<<R.Breadth;
24. R.Display();
25. return 0;
26. }
Private Access Modifier :-
The private keyword is used to crate private members (data and functions).
The private members can only be accessed from within the class.
However, friend classes and friend function can access private members.
1. int Rectangle{
2.
3. int Length, Breadth;
4. publc:
5.
6.
7. void Area(int L, int B)
8. { Length = L; Breadth = B;
9. int area = Length * Breadth;
10. cout<<“Area of the Rectangle is : ”<<area<<endl;
11. }
12. };
13.
14.
15. int main()
16. { Rectangle R;
17. R,Area(10,20);
18. return 0;
19. }
We can access the private data members of a class indirectly using the public members
functions of the class.
Friend class :- A friend class can access private and protected members of other class in which
it is define as friend. It is sometime used to allow a particular class to access private
members of other class.
1. class Animal{
2. int age;
3. int weight;
4. public:
5. Animal()
6. {
7. age = 25;
8. weight = 70;
9. }
10. friend class Dog;
11. };
12.
13. class Dog {
14. public:
15. void display(Animal &t)
16. {
17. cout<<end“Age “<<t.age;
18. cout<<”Weight “<<t.weight;
19. }
20. };
21.
22. int main()
23. { Anial A;
24. Dog D;
25. D.display(A);
26. return 0;
27. }
Friend function :-
Friend Function Like friend class, a friend function can be given a special grant to
access private and protected members A friend function can be:
(a) A member of another class
(b) A global function
• A friend function is a special function in C++ which in-spite of not being member
function of a class has privilege to access private and protected data of a class.
• A friend function is a non member function or ordinary function of a class, which is
declared as a friend using the keyword "friend" inside the class. By declaring a function
as a friend, a II the access permissions are given to the function.
• The keyword "friend" is placed only in the function declaration of the friend function and
not in the function definition.
• When friend function is called neither name of object nor dot operator is used.
However it may accept the object as argument whose value it want to access.
• Friend function can be declared in any section of the class i.e. public or private or
protected.
Syntax:-
Syntax :
class <class_name>
{
friend <return_type> <function_name>(argument/s);
};
1. class Largest
2. {
3. int first, secod, max;
4. public:
5. void set_data(int f, int s)
6. {
7. first = f;
8. second = s;
9. }
10. friend void find_max(largest);
11. };
12.
13. void find_max(Largest t)
14. {
15. if(t.first>t.second)
16. t.maxi=t.first;
17. else
18. t.maxi=t.second;
19.
20. cout<<“Maximum Number is\t”<<t.maxi;
21. }
22.
23. int main()
24. {
25. Largest l;
26. l.set_data(10,20);
27. find_max(l);
28. return 0;
29. }
Protected Access Modifier :-
Protected access modifier is similar to private access modifier,
But the difference is protected members can be access within the class and from the
derived class as well.
1. class animal
2. protected:
3. int age;
4. int weight;
5. public:
6. Animal()
7. {
8. age = 25;
9. weight = 70;
10. }
11. };
12.
13. class Dog:public Animal{
14. public:
15. void display()
16. {
17. cout<<“Age “<<age<<” “<<weight “<<weight<<end;
18. }
19.};
20.
21. int main()
22. { Dog D;
23. D.display();
24. return 0;
25 }
Base class member Type of Inheritance
access
Public Protected Private
specifier
Public Public Protected Private
Protected Protected Protected Private
Not accessible Not accessible Not accessible
Privat
(Hidden) (Hidden) (Hidden)
FINAL Keyword :
C++ 11 allows built in facility to prevent overriding of virtual function wing final
specifier.
1 #include <iostream>
2 using namespace std;
3
4 class Base
5 {
6 public:
7 virtual void myfun( ) final{
8 cout << "myfun() In Base”;
9 }
10 };
11 class Derived : public Base{
12 void myfun(){
13 cout << "myfun() in Derived\n";
14 }
15 };
16
17 int main(){
18 Derived d;
19 Base &b = d;
20 b.myfun();
21 return 0;
22 }
Error : ‘overriding final functions’
1 include <iostream>
2 class Base final-f
3 };
4
5 class Derived : public Base
6 {
7 };
8
9 int main( ){
10 Derived d;
11 return 0;
12 }
13
Error : Cannot define from final base ‘Base’ in defined type ‘Defined’
CANST KEYWORD :
Const keyword used to define the constant value that cannot change during program
execution.
Use of the const keyword with different parameter :
Use const variable
Use const with pointers
Use const pointer with variables
Use const with function arguments
Use const with class member functions
Use const with class data members.
Use const with class objects.
1. Const variable
Const int Q=20 ;
Q=a+10 ;
OUTPUT : error.
2. Const pointer
we cannot change the address of the const pointer after its initialization, which means the
pointer will always point to the same address once the pointer is initialized as the const
pointer.
1 int main ( )
2 {
3 int x = 10, y = 20;
4
5 // const integer ptr variable point address to the variable x
6 int* const ptr = &x;
7
8 //ptr = &y; // now ptr cannot changed their address
9 *ptr = 15; // ptr can only change the value
10 cout << " The value of x: " <<x << endl;
11 cout << " The value of ptr: " << *ptr << endl;
12 return Q;
13 }
14
15
16 OUTPUT:
17 The value of x: 15
18 The value of ptr: 15
3. Pointer to constant variable
It means pointer point to the value of a const variable that cannot change.
Const int* x;
Both are pointer to constant variable
Char const* y;
1 Int main ( )
2 {
3 int x = 7, y = 10;
4
5 // here x become constant variable
6 const int *ptr = &x;
7 cout << " \n The initial value of ptr:" <<*ptr;
8 cout << " \n The value of x: " <<x;
9
10 // *ptr = 15; It is invalid; we cannot directly assign a value to the ptr variable
11 ptr = &y; // here ptr variable pointing to the no const address 'y'
12
13 cout << " \n The value of y: " <<y;
14 cout << " \n The value of ptr:" << *ptr;
15 return 0;
16 }
4. Constant function Arguments
1 Int Test (const int num)
2 {
3 // if we change the value of the const argument, it thwrows an error, num = num + 10;
4 cout << " The value of num: " << num << endl;
5 return 0;
6 }
7 Int main ()
8 {
9 Test(5);
10 }
5. Const pointer pointing to a const variable :
Syntax – const data type const varrame ;
1 int main()
2 {
3 int x = 5;
4 int m =10;
5 const int* const 1 = &x;
6 //i = &m; error
7 //*i=10;
8 // The above statement will give CTE
9 // Once Ptr(*i) value is
10 // assigned, later it can't be modified(Error)
11
12 char y = 'A';
13 const char* const j = &y;
14
15 // *j='B';
16 // The above statement will give CTE
17 // Once Ptr(*j) value is
18 // assigned, later it can't be modified(Error)
19
20 cout <<*t << " and”<< *j
21 return 0;
22 }
6. Pass const-argument value to a non-const parameter of a function cause error :
1 Int foo(int* y){
2 return *y;
3 }
4
5 int main( ){
6 int k = 8;
7 const Int* x = &k;
8 cout << foo(x);
9 return 0;
10 }
11
error : invalid conversion from ‘const int* ’ to ‘int*’
7. For const return type: the return type of the function is const and so it return a const
integer value to us.
1 const Int foo(int y)
2 {
3 y--;
4 return y;
5 }
6
7 int matr<)
8 {
9 int x - 9;
10 const int z = 10;
11 cout << foo(x) << "\n'<< foot (z);
12
13 return 0;
14 }
There will be no issue whether we pass canst or non-const variable to the function
because the value will be returned by the function will be constant automatically. As the
argument of the function is non-const.
8. For const return type and const parameter:
1 const int foo(const int y)
2 {
3 //y—; it will give an error
4 return y;
5 }
6
7 int main()
8 {
9 int x = 9;
10 const int z = 10;
11 cout << foo(x) << '\n'<< foo(z);
12
13 return 0;
14 }
Here, both const and non-const valued can be passed as the const parameter to the
function, but we are not allowed to then change the value of a passed variable because the
parameter is const.
Otherwise, we will face the error.
“y is a const var its value can’t be charged.
Inheritance : In C++, there are 5 types of inheritance.
1. Signal
2. Multilevel
3. Hierarchical
4. Multiple
Not in Java
5. Hybrid
1. Signal : A. Base class
B. Derived class
1 class Human {
2 public:
3 //properties
4 Int age ;
5 Int weight;
6
7 };
8
9 class Male : public Human
10 { public:
11 };
12
13 Int main( )
14 { Male Me;
15 Me.age = 35;
16 Me.weight = 60;
17 cout<<Me.age<<" "<<Me.weight<<endl;
18 }
Output : 35 60
2. Multilevel :
Car
Toyota
Innova
1 class Car {
2 public:
3 string cartype;
4
5 };
6
7 class Toyota : .public Car
8 { public:
9 string country;
10
11 };
12
13 class Innova :public Toyota{
14 public:
15 int price;
16 };
17
18 int main()
19 { Innova In;
28 In.cartype = "Petrol";
21 In.country = "Japan";
22 In.price = 300000;
23 cout«In.cartype<<" "<<In.country<<" "<<In.price<<endl;
24 }
3. Hierarchical : Employee – (i) Intern
(ii) FTE
1 class Employee{
2 public :
3 string Profile;
4
5 }’
6
7 class Intern : public Employee
8 { public:
9 int salary;
10
11 };
12
13 class Fulltime : public Employee{
14 public :
15 int salary;
16 };
17
18 int main()
19 { Fulltime PTE;
29 FTE.salary = 1000000;
21 FTE.Profile = "SDE";
22 Intern ITE;
23 ITE.salary = 500000;
24 ITE.Profile = "SDE";
25 cout<<FTE.Profile<<" "<<FTE.salary<<" "<<endl;
26 cout<<ITE.Profile<<" "<<ITE.salary<<" "<<endl;
27 }
speaks speaks
MOM DAD
Multiple : CHILD
There can be ambiguity, when the Base classes functions have same name, to resolve
this: use scope resolution operator.
1 class Mom{
2 public:
3 void display()
4 { cout<<"Class MOM "<<endl; }
5 };
6
7 class Dad{
8 public:
9 void display()
10 { cout<<"Class DAD "<<endl; }
11 };
12
13 class child :public Mom, public Dad{
14 public:
15 void display()
16 { cout<<"Class CHILD "<<endl; }
17 };
18
19 Int main()
20 { child ch;
21 ch.display();
22 ch.Mom::display( );
23 ch.Dad::display( );
24 }
Hybrid :
Vehicle
Car Racing
1 class Rectanglef
2 int Length,Breadth;
3 public:
A Rectangle()
5 {
6 Length=0;
7 Breadth=0;
8 }
9
10 void operator ++()
11 {
12 Length+=2;
13 Breadth+=2;
14 }
15
16 void Display()
17 {
18 cout<<"\n Length "<<Length;
19 cout<<"\n Breadth "<<Breadth;
20 }
21 };
22
23
24 int main()
25 { Rectangle R;
26 cout<<"\n Length and Breadth before increament ";
27 R.DisplayO;
28 ++R;
29 cout<<"\n Length and Breadth after increament ";
30 R.Display();
31 return 0;
32 }
But, among them, there are some operators that cannot be overloaded. They are
• Scope resolution operator ::
• Member selection operator
• Member selection through *
Pointer to member variable
• Conditional operator ?:
• Size of operator size of()
Operators that can be overloaded
1. Binary Arithmetic -> +,-,*,/,%
2. Unary Arithmetic -> +,-,++,-
3. Assignment -> =, +=,*=, /= ,̶ =, %=
4. Bit-wise -> &, I,A
5. De-referencing -> (->)
6. Dynamic memory allocation and De-allocation -> New, delete
7. Subscript -> []
8. Function call -> ()
9. Logical -> &, I lr!
10. Relational -> >,<, = =,<=,>=
Why can't the above-stated operators be overloaded?
1. size of - This returns the size of the object or data type entered as the operand This is
evaluated by the compiler and cannot be evaluated during runtime. The proper
incrementing of a pointer in an array of objects relies on the size of operator implicitly.
Altering its meaning using overloading would cause a fundamental part of the language
to collapse.
2. type of: This provides a CPP program with the ability lo recover the actual derived
type of the object referred to by a pointer or reference. For this operator, the whole point
is to uniquely identify a type. If we want to make a user-defined type "look" like another
type, polymorphism can be used but the meaning of the typed operator must remain
unaltered, or else serious issues could arise.
3. Scope resolution (::): This helps identify and specify the context to which an
identifier refers by specifying a namespace It is completely evaluated at runtime and
works on names rather than values. The operands of scope resolution are note expressions
with data types and CPP has no syntax for capturing them if it were overloaded. So it is
syntactically impossible to overload this operator.
4. Class member access operators (.(dot), .* (pointer to member operator)): The
importance and implicit use of class member access operators can be understood through
the following example:
Important points about operator overloading
1) For operator overloading to work, at least one of the operands must be a user-defined
class object.
2) Assignment Operator: Compiler automatically creates a default assignment operator
with every class. The default assignment operator does assign all members of the right
side to the left side and works fine in most cases (this behaviour is the same as the copy
constructor). See ibis for more details.
3) Conversion Operator: We can also write conversion operators that can be used to
convert one type to another type. Overloaded conversion operators must be a member
method. Other operators can either be the member method or the global method.
4) Any constructor that can be called with a single argument works as a conversion
constructor, which means it can also be used for implicit conversion to the class being
constructed.
Runtime Polymorphion :
It is achieved by function overriding.
Function overriding :
Function overriding occurs when a derived class has a definition for one of the member
functions of the base class. That base function is said to be overridden.
1 class Animal{
2 public:
3 int age;
4 int weight;
5
6 void speak()
7 {
8 cout<<"HIIII "<<endl;
9 }
10 };
11
12 class Dog : public Aninal{
13 public:
14 void speak()
15 {
16 cout<<- WOOF "<<endl;
17 }
18 };
19
20 int main()
21 { Dog D;
22 D.speakO;
23 return 0;
24 }
Rules Most do inheritance.
same function name/same parameter.
Q. Can we overtime static method?
Virtual Function : A virtual function is a member function, which is declare within a base class
and is overridden by a derived class.
When we refer to a derived class object wing a pointer or a reference to the base class, we
can call a virtual function for that object and execute the derived class’s version of the
function.
They are mainly use to achieve Run-time polymorphion. The resolving of unction call is
done at runtime.
Functions are declared with a virtual keyword in the base class.
Points to remember :
1. Virtual functions cannot be static.
2. Virtual function can be a friend function of another class.
3. They are always defined in the base class and overridden in a derived class. (we
may/may not override in the derived class, optional).
4. A class may have virtual destructor, but it cannot have a virtual constructor.
1 include <iostream>
2 using namespace std;
3
4 class Shape {
5 public:
6 int get_Area(){
7 cout <<"This is call to parent class area\n";
8 return 1;
9 }
10 };
11
12 class Square : public Shape {
13 int area=0;
14 public:
15 Square(int 1, int b)
16 { area = l*b;
17 }
18 int get_Area(){ cout <<"Square area: " << area « '\n';
19 return area;
20 }
21 };
22 int main()
23 {
24 Shape* s;
25 Square sq(5, 5);
26 s = &sq;
27 s->get_Area();
28 return 0;
29 }
OUTPUT : This is call to parent class area
1 #include <iostream>
2 using namespace std;
3
4 class Shape {
5 public:
6 virtual int get_Area(){
7 cout << "This is call to parent class area\n";
8 return 1;
9 }
16 };
11
12 class Square : public Shape {
13 int area=0;
14 public:
15 Square(int I, int b)
16 { area = l*b;
17 }
18 int get_Area( ){ cout <<"Square area: " << area << '\n';
19 return area;
26 }
21 };
22 int main( )
23 {
24 Shape* s;
25 Square sq(5, 5);
26 s = &sq;
27 s->get_Area( );
28 return 0;
29 }
OUTPUT : Square area :25.
Use of virtual function?
It allows us to create a list of base class pointers and call methods of any derived classes
without even knowing the kind of derived class object.
Working of virtual functions (concepts of VTABLE and VPTR).
If a class contains a virtual function then the compiler itself does two things.
1. It object of the class is created then a virtual pointer (VPTR) is inserted as a data
member of the class to point to VTABLE of that class.
For each mew object created, a new virtual pointer is inserted as a data member of that
class. Virtual pointer is inherited by derived classes.
2. Irrespective of object is created or not, class contains as a member a static array of
function pointers called VTABLE.
Virtual Table : A table created at compile time for every single class containing the
most derived versions of virtual function only.
A virtual table contains one entry for each virtual function that can be called by object of
the class.
1 #lnclude<iostream>
2 using namespace std;
3
4 class base {
5 public:
6 void fun_l()
7 { cout<< “base-l\n"; >
8
9 virtual void fun_2() {
10 cout << "bose-2\n"; }
11
12 virtual void fun_3() {
13 cout << "ba$e-3\n"; >
14
15 virtual void fun_4()
16 { cout << "base-4\n"; }
17 };
18
19 class derived : public base {
20 public:
21 void fun_l()
22 { cout <<“derlved-l\n"; >
23
24 void fun_2()
25 { cout << "derlved-2\n"; }
26
27 void fun_4(int x)
28 { cout << "derlved-4\n"; >
29 };
30
31 int moin( )
32 {
33 base *p;
34 derived objl;
35 p = &obj 1;
36
37 p->fun_l();
38 p->fun_2();
39 p->fun_3();
40 p->fun_4();
41
42 return 0;
43 }
44
address of
base version
of func(2) VTABLE for
class base
address of
base version
of func(3)
address of
base version
of func(4)
OBJ 1
address of
P
vptr derived version
of func(2)
address of VTABLE for
base version class base
of func(3)
address of
base version
of func(4)
Virtual Destructor : Deleting a derived class objects using a pointer of base class type that has a
non-virtual destructor results in undefined behaviour.
1 include <iostream>
2 using namespace std;
3
4 class base {
5 public:
6 base()
7 { cout << "Constructing base\n"; }
8 ~base()
9 { cout<< "Destructing base\n"; >
10 };
11
12 class derived: public base {
13 public:
14 derived( )
15 { cout << "Constructing derived\n"; >
16 ~derived()
17 { cout << "Destructing derived\n"; }
18 };
19
20 int main( ){
21 base *b = new derived( );
22 delete b;
23 getchar();
24 return 0;
25 }
26
OUTPUT : Constructing base
Constructing derived
Destructing base
NOTE : The base class pointer was used to make the derived class object.
Destructor has to be made virtual, otherwise Derive destructor will not call.
1 include <iostream>
2 using namespace std;
3
4 class base {
5 public:
6 base( )
7 { cout << "Constructing base\n"; >
8 virtual ~base()
9 { cout<< "Destructing base\n"; }
10 };
11
12 class derived: public base {
13 public:
14 derived( )
15 { cout << "Constructing derived\n"; }
16 ~derived()
17 { cout << "Destructing derived\n"; >
18 };
19
20 int main(){
21 base *b = new derived();
22 delete b;
23 getchar( );
24 return 0;
25 }
26
OUTPUT : Constructing base
Constructing derived
Destructing derived
Destructing base
Q. What about Virtual Constructor?
It is not possible because when a constructor of a class is executed there is no virtual
table in the memory, means no virtual pointer defined yet, So constructor should always
be non-virtual.
Because the object is not created, virtual construction is impossible.
The compiler must know the type of object before creating it.
Error – Constructor cannot be declared ‘Virtual’.
Encapsulation : Encapsulation is defined as wrapping up of data and information under a signal
unit.
1 class Addition{
2 public:
3 Addition(int t =0) {
4 total = t;
5 }
6
7 void addNum(int number) {
8 total += number;
9 }
10
11 int getTotal() {
12 return total;
13 };
14
15 private:
16 int total;
17 };
18
19 int main() {
20 Addition a;
21
22 a.addNum(3);
23 a.addNum(2);
24 a.addNum(8);
25
26 cout << 'Total " << a.getTotal() <<endl;
27 return 0;
28 }
Role of access specifies in encapsulation :
The process of implementing encapsulation can be sub-divided into two steps:
1. The data members should be labeled as private wing the private access specifiers.
2. The member function which manipulates the data members should be labeled as
public wing the public access specifier.
Data encapsulation led to the important OOP concept of data hiding.
We can write “read only” or “write only” methods to implement data hiding.
Abstraction : Abstraction is a process of providing only the essential details to the outside world
and hiding the internal details
C++ provides a great level of abstraction for ex-pow () function is used to calculate the
power of a number without knowing the algorithm the function follow.
Data Abstraction can be achieved in two ways :
Abstraction wing classes.
Abstraction in header files
1 #include <iostream>
2 #lnclude<math.h>
3 using namespace std;
4 int main()
5 {
6 int n - 4;
7 int power = 3;
8 int result = pow(n,power);
9 // pow(n,power) is the power function
10 std::cout <<"Cube of n is : " <<result<< std::endl;
11 return 0;
12 }
1 #include <iostream>
2 using namespace std;
3 class Sum
4 {
5 private: int x, y, z; // private variables
6 public:
7 void add() {
8 cout<<"Enter two numbers: ";
9 cln>>x>>y;
10 z= x+y;
11 cout<<"Sum of two number is: "<<z<<endl;
12 }
13 };
14 int main( ) {
15 Sum sm;
16 sm.add( );
17 return 0;
18 }
We are not allowed to access x,y,z directly however, we can access them wing member
function of the class.
Advantages o Data Abstraction :
A programmer does not need to write the low level code.
Data Abstraction avoids code duplication.
Increase reusability.
Implemention details of the class are protected from the inadvertent user level errors.