ACCESSOR FUNCTIONS are those member functions that allow us to access the data number (field) of object.They cannot change the value of data members.they are used to read the values of private data members of a class which are not directly accessible in non member function.
Eg:
class student
{
Private:
int rollno; float marks;char grade;
public :
void readstudent()
{ ……}
void dispstudent()
{….}
int getRollno()
{return rollno;} (((accessor method)
float get_Marks()
{return marks;} …….
void calcgrade()
{
if (marks>=75) grade=’O’;
else if (marks>=50) grade= ‘A’; ((mutator method --- modifying a data member grade))
else if(marks>=40) grade=’B’;
else grade=’C’;
}
MUTATOR FUNCTIONS are the member functions that allow us to change the data members of an object.
Manager functions are member functions with specific functions
Eg: constructor and destructor
INHERITANCE AND ACCESS CONTROL
When a class inherits from some members from another class there must be a way to control the access of inherited members.One such access control mechanism is the way derived class are declared
ACCESS CONTROL IN PUBLICLY DERIVED CLASS
A class is publicly derived when the keyword public precedes the base class name in the class definition.
class manager : public employee, public person
{
………………
}
#include<iostream.h>
#include<stdio.h>
Const int Len=25;
class employ
{
private : char name[Len]; unsigned long enumb;
public:
void getdata()
{cout<<”enter name and emp number”;
gets(name);
cin>>enumb;
}
void putdata()
{cout<<”name”<<name<<”emp num”<<enumb<<”basic sal”<<basic;
}
protected : float basic;
void getbasic()
{cout<<”enter basic”; cin>>basic;}
};
class manager : public employee {
private:
char title[Len];
public :
void getdata()
{ employee :: getdata(); \\ this is because manager class also has getdata()((to resolve the identity as
manager also has getdata()))))
getbasic();
cout <<”enter title”;
gets(title);
}
void putdata()
{
employee::putdata();\\ this is because manager class also has putdata()
cout<<title;
}
};
int main()
{
manager m1,m2;
cout<<”manager1”;
m1.getdata();
cout<<”manager2”;
m2.getdata();
cout<<”manager1 details”;
m1.putdata();
cout<<”manager2 details”;
m2.putdata();
return 0;
}
In this program public members of class employee(getdata() and putdata()) become the public members of publicly derived class manager and protected members(basic and getbasic()) of employee become protected members of manager class. The private members of base class employee can also be indirectly accessed by member functions employee::getdata (which gives name and enumb ehich are private members).
ACCESS CONTROL IN PRIVATELY DERIVED CLASS
A class is privately derived when the keyword privateprecedes the base class name in the class definition.
class manager : private employee
{
………………
}
#include<iostream.h>
#include<stdio.h>
Const int Len=25;
class employ
{
private : char name[Len]; unsigned long enumb;
public:
void getdata()
{cout<<”enter name and emp number”;
gets(name);
cin>>enumb;
}
void putdata()
{cout<<”name”<<name<<”emp num”<<enumb<<”basic sal”<<basic;
}
protected : float basic;
void getbasic()
{cout<<”enter basic”; cin>>basic;}
};
class manager :private employee {
private:
char title[Len];
public :
void getdata()
{ employee :: getdata(); \\ this is because manager class also has getdata()((to resolve the identity as
manager also has getdata()))))
getbasic();
cout <<”enter title”;
gets(title);
}
void putdata()
{
employee::putdata();\\ this is because manager class also has putdata()
cout<<title;
}
};
int main()
{
manager m1,m2;
cout<<”manager1”;
m1.getdata();
cout<<”manager2”;
m2.getdata();
cout<<”manager1 details”;
m1.putdata();
cout<<”manager2 details”;
m2.putdata();
return 0;
}
VIRTUAL BASE CLASSES
When multiple base classes are inherited an element of ambiguity can be formed. For eg:
#include<iostream.h>
class Base{
public : int a;
}
class D1: public Base{
public : int b;
}
class D2: public Base
{
public : int c;
}
class D3: public D1,public D2 //here there are two copies of Base in D3;
{
public : int total;
}
void main()
{ D3 .ob;
ob.a=25; // here a is in D2 and D1 and D3 inherits from both D! and D2
ob.b=50; ob.c=75;
ob.total=ob.a+ob.b+ob.c; cout<<ob.total;
getch();
}
To solve this problem use virtual classes
When 2 or more objects are derived from a common base class you can prevent multiple copies of base class from being present in an object derived from those objects by declairing the base class as virtual when they are inherited.
Base class
Virtual D1 virtual D2
D3
#include<iostream.h>
class Base{
public : int a;
}
class D1: virtual public Base{
public : int b;
}
class D2: virtual public Base
{
public : int c;
}
class D3: public D1,public D2
{
public : int total;
}
void main()
{ D3 .ob;
ob.a=25; // here a is in D2 and D1 and D3 inherits from both D! and D2
ob.b=50; ob.c=75;
ob.total=ob.a+ob.b+ob.c; cout<<ob.total;
getch();
}
NAME SPACES
Namespaces allow to group entities like classes, objects and functions under a name. This way the global scope can be divided in "sub-scopes", each one with its own name.
The format of namespaces is:
namespace identifier
{
entities
}
Where identifier is any valid identifier and entities is the set of classes, objects and functions that are included within the namespace.
The format of namespaces is:
namespace identifier
{
entities
}
Where identifier is any valid identifier and entities is the set of classes, objects and functions that are included within the namespace.
The functionality of namespaces is especially useful in the case that there is a possibility that a global object or function uses the same identifier as another one, causing redefinition errors. For example:
#include <iostream>
using namespace std;
namespace first
{
int var = 5;
}
namespace second
{
double var = 3.1416;
}
int main () {
cout << first::var << endl;
cout << second::var << endl;
return 0;
}
In this case, there are two global variables with the same name: var. One is defined within the namespace first and the other one in second. No redefinition errors occurs here because of namespaces
Abstract classes
An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier (= 0) in the declaration of a virtual member function in the class declaration.
class AB {
public:
virtual void f() = 0;
};
Abstract classes act as expressions of general concepts from which more specific classes can be derived. You cannot create an object of an abstract class type; however, you can use pointers and references to abstract class types.
A class that contains at least one pure virtual function is considered an abstract class. Classes derived from the abstract class must implement the pure virtual function or they, too, are abstract classes.
class Account {
public:
Account( double d ); // Constructor.
virtual double GetBalance(); // Obtain balance.
virtual void PrintBalance() = 0; // Pure virtual function.
private:
double _balance;
};
The only difference between this declaration and the previous one is that PrintBalance is declared with the pure specifier (= 0).
INLINE FUNCTIONS
Inline functions are functions where the call is made to inline functions. The actual code then gets placed in the calling program.Inline function is the optimization technique used by the compilers. One can simply prepend inline keyword to function prototype to make a function inline. Inline function instruct compiler to insert complete body of the function wherever that function got used in code.
Advantages :-
1) It does not require function calling overhead.
2) It also save overhead of variables push/pop on the stack, while function calling.
3) It also save overhead of return call from a function.
4) It increases locality of reference by utilizing instruction cache.
5) After in-lining compiler can also apply intraprocedural optmization if specified. This is the most important one, in this way compiler can now focus on dead code elimination, can give more stress on branch prediction, induction variable elimination etc..
Disadvantages :-
1) May increase function size so that it may not fit on the cache, causing lots of cahce miss.
2) After in-lining function if variables number which are going to use register increases than they may create overhead on register variable resource utilization.
3) It may cause compilation overhead as if some body changes code inside inline function than all calling location will also be compiled.
4) If used in header file, it will make your header file size large and may also make it unreadable.
5) If somebody used too many inline function resultant in a larger code size than it may cause thrashing in memory. More and more number of page fault bringing down your program performance.
6) Its not useful for embeded system where large binary size is not preferred at all due to memory size constraints.
Advantages :-
1) It does not require function calling overhead.
2) It also save overhead of variables push/pop on the stack, while function calling.
3) It also save overhead of return call from a function.
4) It increases locality of reference by utilizing instruction cache.
5) After in-lining compiler can also apply intraprocedural optmization if specified. This is the most important one, in this way compiler can now focus on dead code elimination, can give more stress on branch prediction, induction variable elimination etc..
Disadvantages :-
1) May increase function size so that it may not fit on the cache, causing lots of cahce miss.
2) After in-lining function if variables number which are going to use register increases than they may create overhead on register variable resource utilization.
3) It may cause compilation overhead as if some body changes code inside inline function than all calling location will also be compiled.
4) If used in header file, it will make your header file size large and may also make it unreadable.
5) If somebody used too many inline function resultant in a larger code size than it may cause thrashing in memory. More and more number of page fault bringing down your program performance.
6) Its not useful for embeded system where large binary size is not preferred at all due to memory size constraints.
#include <iostream.h>
int exforsys(int);
void main( )
{
int x;
cout << “\n Enter the Input Value: ”;
cin>>x;
cout<<”\n The Output is: “ << exforsys(x);
}
int exforsys(int);
void main( )
{
int x;
cout << “\n Enter the Input Value: ”;
cin>>x;
cout<<”\n The Output is: “ << exforsys(x);
}
inline int exforsys(int x1)
{
return 5*x1;
}
{
return 5*x1;
}
TEMPLATE CLASSES
C++ Class Templates are used where we have multiple copies of code for different data types with the same logic. If a set of functions or classes have the same functionality for different data types, they becomes good candidates for being written as Templates
Declaration of C++ class template should start with the keyword template. A parameter should be included inside angular brackets. The parameter inside the angular brackets, can be either the keyword class or typename. This is followed by the class body declaration with the member data and member functions. The following is the declaration for a sample Queue class.
This is an example of class that acts on integer data only
class calc
{
public:
int multiply(int x, int y);
int add(int x, int y);
};
int calc::multiply(int x, int y)
{
return x*y;
}
int calc::add(int x, int y)
{
return x+y;
}
If we want to change this to work on floating point also then
template <class A_Type> class calc
{
public:
A_Type multiply(A_Type x, A_Type y);
A_Type add(A_Type x, A_Type y);
};
template <class A_Type> A_Type calc<A_Type>::multiply(A_Type x,A_Type y)
{
return x*y;
}
template <class A_Type> A_Type calc<A_Type>::add(A_Type x, A_Type y)
{
return x+y;
}
VIRTUAL DESTRUCTOR
"A destructor is a member function of a class, which gets called when the objest goes out of scope”
A destructor for a class should be virtual when an object of a derived class will be destroyed by invoking the base class destructor. The destructor must be virtual when you delete a pointer to an object and it is possible that it points to a derived class.
#include<iostream.h>
class Base_class
{
public:
Base_class(){ cout<<"Constructor: Base_class"<<endl;}
// virtual keyword is needed here
virtual ~ Base_class(){ cout<<"Destructor : Base_class"<<endl;}
};
class Derived_class: public Base_class
{ public:
Derived_class(){ cout<<"Constructor: Derived_class"<<endl;}
~ Derived_class(){ cout<<"Destructor : Derived_class"<<endl;}
};
void main()
{
Base_class *p = new Derived_class();
delete p;
}
#include<iostream.h>
class Base_class
{
public:
Base_class(){ cout<<"Constructor: Base_class"<<endl;}
// virtual keyword is needed here
virtual ~ Base_class(){ cout<<"Destructor : Base_class"<<endl;}
};
class Derived_class: public Base_class
{ public:
Derived_class(){ cout<<"Constructor: Derived_class"<<endl;}
~ Derived_class(){ cout<<"Destructor : Derived_class"<<endl;}
};
void main()
{
Base_class *p = new Derived_class();
delete p;
}
Observe the use of the virtual keyword in the example in Step 3. If the destructor of the base class were not declared as virtual, the destructor of the derived class would not get called.
RUN TIME AND COMPILE TIME POLY MORPHISM
RUN TIME AND COMPILE TIME POLY MORPHISM
Polymorphism is defined as one interface to control access to a general class of actions. There are two types of polymorphism one is compile time polymorphism and the other is run time polymorphism. Compile time polymorphism is functions and operators overloading. Runtime time polymorphism is done using inheritance and virtual functions.
Polymorphism means that functions assume different forms at different times. In case of compile time it is called function overloading. For example, a program can consist of two functions where one can perform integer addition and other can perform addition of floating point numbers but the name of the functions can be same such as add. The function add() is said to be overloaded. Two or more functions can have same name but their parameter list should be different either in terms of parameters or their data types. The functions which differ only in their return types cannot be overloaded. The compiler will select the right function depending on the type of parameters passed. In cases of classes constructors could be overloaded as there can be both initialized and uninitialized objects. Here is a program which illustrates the working of compile time function overloading and constructor overloading.
FUNCTION OVERLOADING EXAMPLES
Polymorphism means that functions assume different forms at different times. In case of compile time it is called function overloading. For example, a program can consist of two functions where one can perform integer addition and other can perform addition of floating point numbers but the name of the functions can be same such as add. The function add() is said to be overloaded. Two or more functions can have same name but their parameter list should be different either in terms of parameters or their data types. The functions which differ only in their return types cannot be overloaded. The compiler will select the right function depending on the type of parameters passed. In cases of classes constructors could be overloaded as there can be both initialized and uninitialized objects. Here is a program which illustrates the working of compile time function overloading and constructor overloading.
FUNCTION OVERLOADING EXAMPLES
A function name having several definitions that are differentiable by the number or types of arguments. Either the number of data members is different or data type is different
C++ permits the use of two function with the same name. However such functions essentially have different argument list. The difference can be in terms of number or type of arguments or both.
This process of using two or more functions with the same name but differing in the signature is called function overloading.
But overloading of functions with different return types are not allowed.
In overloaded functions , the function call determines which function definition will be executed.
The biggest advantage of overloading is that it helps us to perform same operations on different datatypes without having the need to use separate names for each version.
This process of using two or more functions with the same name but differing in the signature is called function overloading.
But overloading of functions with different return types are not allowed.
In overloaded functions , the function call determines which function definition will be executed.
The biggest advantage of overloading is that it helps us to perform same operations on different datatypes without having the need to use separate names for each version.
Example different number of arguments
Following code overloads a function area to compute areas of circle , rectangle and triangle
float area(float radius)
{
return 3.14 * radius* radius;
}
float area(float length,float breadth)
{
return length*breadth;
}
float area(float side1,float side2,float side3)
float &= (side1 +side2+ side3)/2;
float ar=sqrt(& * (&_side1)* (& * (&_side2)* (& * (&_side3));
ret ar;
}
Example with different types of arg
#include <iostream>
using namespace std;
void print(int i) {
cout << " Here is int " << i << endl;
}
void print(double f) {
cout << " Here is float " << f << endl;
}
void print(char* c) {
cout << " Here is char* " << c << endl;
}
int main() {
print(10);
print(10.10);
print("ten");
}
FRIEND FUNCTIONS
A friend function is a function that is not a member of a class but has access to the class's private and protected members. Friend functions are not considered class members; they are normal external functions that are given special access privileges. Friends are not in the class's scope, and they are not called using the member-selection operators (. and –>) unless they are members of another class. A friend function is declared by the class that is granting access. The frienddeclaration can be placed anywhere in the class declaration. It is not affected by the access control keywords.
A friend function is used for accessing the non-public members of a class. A class can allow non-member functions and other classes to access its own private data, by making them friends. Thus, a friend function is an ordinary function or a member of another class
class exforsys
{
private:
int a,b;
public:
void test()
{
a=100;
b=200;
}
friend int compute(exforsys e1)
{
private:
int a,b;
public:
void test()
{
a=100;
b=200;
}
friend int compute(exforsys e1)
//Friend Function Declaration with keyword friend and with the object of class exforsys to which it is friend passed to it
};
};
int compute(exforsys e1)
{
//Friend Function Definition which has access to private data
return int(e1.a+e2.b)-5;
}
main()
{
exforsys e;
e.test();
cout<<"The result is:"<<compute(e);
</compute(e);
//Calling of Friend Function with object as argument.
}
{
//Friend Function Definition which has access to private data
return int(e1.a+e2.b)-5;
}
main()
{
exforsys e;
e.test();
cout<<"The result is:"<<compute(e);
</compute(e);
//Calling of Friend Function with object as argument.
}
The function compute() is a non-member function of the class exforsys. In order to make this function have access to the private data a and b of class exforsys , it is created as a friend function for the class exforsys. As a first step, the function compute() is declared as friend in the class exforsys as:
friend int compute (exforsys e1)
The keyword friend is placed before the function. The function definition is written as a normal function and thus, the function has access to the private data a and b of the class exforsys. It is declared as friend inside the class, the private data values a and b are added, 5 is subtracted from the result, giving 295 as the result.
The following example overloads the + operator to add two complex numbers and returns the result.#include <iostream>
using namespace std;
struct Complex {
Complex( double r, double i ) : re(r), im(i) {}
Complex operator+( Complex &other );
void Display( ) { cout << re << ", " << im << endl; }
private:
double re, im;
};
// Operator overloaded using a member function
Complex Complex::operator+( Complex &other ) {
return Complex( re + other.re, im + other.im );
}
int main() {
Complex a = Complex( 1.2, 3.4 );
Complex b = Complex( 5.6, 7.8 );
Complex c = Complex( 0.0, 0.0 );
c = a + b;
c.Display();
}
No comments:
Post a Comment