Beruflich Dokumente
Kultur Dokumente
Ans –
Hierarchial Inheritance
Multilevel Inheritance
The derived class can also have multiple parents which is known as
multiple inheritance. Here the child or derived class has two or more
parent classes. The child class inherits all the properties of all its parents.
Multiple inheritance is implemented same as single inheritance except
that both the parent names have to be specified while defining the class.
We will discuss multiple inheritance in detail in the next unit.
Ans –
Pointers can point to userdefined objects as well. If we would like to define a pointer to an
object of class employee, we would use the following statement:
employee *ptr;
To access the member functions through the pointer there is simple operator -> which is
known as membership access operator. This can be used instead of dot operator when using
pointers to access the member data or functions.
The following statement accesses member function display of the employee class through
the pointer ptr:
ptr->display();
Another important use of pointers is creating datastructures like linked list. Linked list is a
dynamic data structure which can be imagined as set of nodes. Every node stores data and
link to the next node in the list. The following example implements the node using a
structure and linklist using class that stores pointer to the first node in the list.
//linklist.cpp
# include<iostream.h>
# include<conio.h>
struct node
{
int data;
node* next; // pointer to next node
};
class list
{ private:
node *first; // pointer to the first node in the list
public:
list() // no-argument default constructor
{ first=NULL;} // empty list : no first node
void additem(int d) // adds new node to the beginning of the list
{
node* newnode; // node pointer
newnode = new node; // create a new node
newnode->data=d; //assign value
newnode->next=first; // assign pointer to the first
first=newnode; // first now points to new node
}
void display() // displays all nodes
{ node* temp; // pointer to node
temp=first;
while (temp!=NULL)
{ cout<< endl<<temp->data; // print data
temp=temp->next; // points to next node
}
}
};
void main()
{ clrscr();
list list1;
list1.additem(25);
list1.additem(50);
list1.additem(52);
list1.display();
getch();
}
Every object created has a unique pointer created by default known as this pointer.This
pointer is a default pointer created for every object that points to the object itself. All the
member functions have access to “this pointer”. It is useful to return the object itself after
modification. The following program shows the use of this pointer to overload assignment
operator =:
# include<iostream.h>
class alpha
{ private:
int data;
public:
alpha() {data=0;}
alpha (int d) {data=d;}
alpha& operator = (alpha& a)
{ data= a.data;
return *this;}
};
void main()
{alpha a1(37), a2;
a2=a1;
a2.display();
}
Ans –
Virtual Functions
#include <iostream>
using namespace std;
struct A {
void f() { cout << "Class A" << endl; }
};
struct B: A {
void f() { cout << "Class B" << endl; }
};
void g(A& arg) {
arg.f();
}
int main() {
B x;
g(x);
}
Class A
When function g() is called, function A::f() is called, although the argument
refers to an object of type B. At compile time, the compiler knows only
that the argument of function g() will be a reference to an object derived
from A; it cannot determine whether the argument will be a reference to
an object of type A or type B. However, this can be determined at run
time. The following example is the same as the previous example,
except that A::f() is declared with the virtual keyword:
#include <iostream>
using namespace std;
struct A {
virtual void f() { cout << "Class A" << endl; }
};
struct B: A {
void f() { cout << "Class B" << endl; }
};
void g(A& arg) {
arg.f();
}
int main() {
B x;
g(x);
}
Class B
#include <iostream>
using namespace std;
struct A {
virtual void f() { cout << "Class A" << endl; }
};
struct B: A {
void f(int) { cout << "Class B" << endl; }
};
struct C: B {
void f() { cout << "Class C" << endl; }
};
int main() {
B b; C c;
A* pa1 = &b;
A* pa2 = &c;
// b.f();
pa1->f();
pa2->f();
}
Class A
Class C
The function B::f is not virtual. It hides A::f. Thus the compiler will
not allow the function call b.f(). The function C::f is virtual; it overrides A::f
even though A::f is not visible in C.
#include <iostream>
using namespace std;
struct A { };
class B : private A {
friend class D;
friend class F;
};
A global_A;
B global_B;
struct C {
virtual A* f() {
cout << "A* C::f()" << endl;
return &global_A;
}
};
struct D : C {
B* f() {
cout << "B* D::f()" << endl;
return &global_B;
}
};
struct E;
struct F : C {
// Error:
// E is incomplete
// E* f();
};
struct G : C {
// Error:
// A is an inaccessible base class of B
// B* f();
};
int main() {
D d;
C* cp = &d;
D* dp = &d;
A* ap = cp->f();
B* bp = dp->f();
};
B* D::f()
B* D::f()
The statement A* ap = cp->f() calls D::f() and converts the pointer returned
to type A*. The statement B* bp = dp->f() calls D::f() as well but does not
convert the pointer returned; the type returned is B*. The compiler would
not allow the declaration of the virtual function F::f() because E is not a
complete class. The compiler would not allow the declaration of the
virtual function G::f() because class A is not an accessible base class of B
(unlike friend classes D and F, the definition of B does not give access to
its members for class G).
If a function is declared virtual in its base class, you can still access it
directly using the scope resolution (::) operator. In this case, the virtual
function call mechanism is suppressed and the function implementation
defined in the base class is used. In addition, if you do not override a
virtual member function in a derived class, a call to that function uses
the function implementation defined in the base class.
· Defined
· Declared pure
Polymorphism
In simple terms, polymorphism lets you treat derived class members just
like their parent class’s members.
(In C++, for instance, this is possible because the interface definition for
a class defines a memory layout, the virtual function table describing
where pointers to functions can be found. Future, new classes can work
with old, precompiled code because the new classes must conform to the
abstract class interface, meaning that the layout of the new class’s
virtual function table is the same as before; the old, precompiled code
can still look at the same memory offsets relative to the start of the
object’s memory in order to find a pointer to the new function. It is only
that the new virtual function table points to a new implementation of the
functions in the table, thus allowing new, interface-compliant behavior
with old, precompiled code.)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Animal {
public:
Animal(const string & name) : name(name) { }
virtual ~Animal() { }
virtual const string talk() = 0;
const string name;
};
class Cat : public Animal {
public:
Cat(const string & name) : Animal(name) { }
virtual ~Cat() { }
virtual const string talk() { return "Meow!"; }
};
class Dog : public Animal {
public:
Dog(const string & name) : Animal(name) { }
virtual ~Dog() { }
virtual const string talk() { return "Arf! Arf!"; }
};
// prints the following:
//
// Missy: Meow!
// Mr. Bojangles: Meow!
// Lassie: Arf! Arf!
int main() {
Animal * animals [] = {
new Cat("Missy"),
new Cat("Mr. Bojangles"),
new Dog("Lassie")
};
for(int i = 0; i < 3; i++)
cout << animals[i]->name << ": " << animals[i]->talk() << endl;
for(int i = 0; i < 3; i++)
delete animals[i];
return 0;
}
Note that the talk() method is explicitly declared as virtual. This is because
polymorphic method calls have relatively high overhead in C++. This
overhead is lessened by treating all method calls as non-polymorphic,
unless explicitly marked as virtual by the developer.
Ans –
#include<iostream.h>
#include<fstream.h>
#include<conio.h>
#include<stdio.h>
#include<process.h>
#include<string.h>
struct student
{ int rollno;
char name[20];
int marks;
}s;
void main()
{ ifstream fin;
ofstream fout;
int ch,no;
do
{ clrscr();
cout<<"\nMenu\n";
cout<<"\n1. Add";
cout<<"\n2. Search";
cout<<"\n3. Display";
cout<<"\n4. Exit";
cout<<"\n\nEnter your choice: ";cin>>ch;
switch(ch)
{ case 1:
{ cout<<"\nEnter rollno. :";cin>>s.rollno;
cout<<"\nName: ";gets(s.name);
cout<<"\nMarks: ";cin>>s.marks;
fout.open("student.dat",ios::binary|ios::app);
fout.write((char*)&s,sizeof(student));
fout.close();
break;
}
case 2:
{ cout<<"\nEnter rollno. to be searched: ";cin>>no;
fin.open("student.dat",ios::binary|ios::in);
while(!fin.eof())
{ fin.read((char*)&s,sizeof(student));
if (s.rollno==no)
{ cout<<"\nRollno: "<<s.rollno;
cout<<"\nName: "<<s.name;
cout<<"\nMarks: "<<s.marks;
getch();
break;
}
}
fin.close();
break;
}
case 3:
{ fin.open("student.dat",ios::binary|ios::in);
while(!fin.eof())
{ clrscr();
fin.read((char*)&s,sizeof(student));
cout<<"\nRoll No. :"<<s.rollno;
cout<<"\nName: "<<s.name;
cout<<"\nMarks: "<<s.marks;
getch();
}
fin.close(); break;
}
case 4:exit(0);
} while (ch<=4);
}
Ans –
Throwing an Exception
Catching an Exception
try {
Exception handlers
Each catch clause (exception handler) is like a little function that takes a
single argument of one particular type. The identifier (id1, id2, and so on)
may be used inside the handler, just like a function argument, although
sometimes there is no identifier because it’s not needed in the handler –
the exception type gives you enough information to deal with it.
The handlers must appear directly after the try block. If an exception is
thrown, the exception handling mechanism goes hunting for the first
handler with an argument that matches the type of the exception. Then
it enters that catch clause, and the exception is considered handled.
(The search for handlers stops once the catch clause is finished.) Only
the matching catch clause executes; it’s not like a switch statement
where you need a break after each case to prevent the remaining ones
from executing. Notice that, within the try block, a number of different
function calls might generate the same exception, but you only need one
handler.
Ans –
Uncaught Exceptions
terminate()
set_terminate()
You can install your own terminate() function using the standard
set_terminate() function, which returns a pointer to the terminate()
function you are replacing, so you can restore it later if you want. Your
custom terminate() must take no arguments and have a void return
value. In addition, any terminate() handler you install must not return or
throw an exception, but instead must call some sort of program-
termination function. If terminate() is called, it means the problem is
unrecoverable. Like unexpected(), the terminate() function pointer
should never be null.
//: C07:Trmnator.cpp
// Use of set_terminate()
#include <exception>
#include <iostream>
#include <cstdlib>
using namespace std;
void terminator() {
cout << "I’ll be back!" << endl;
abort();
}
void (*old_terminate)()
= set_terminate(terminator);
class Botch {
public:
class Fruit {};
void f() {
cout << "Botch::f()" << endl;
throw Fruit();
}
~Botch() { throw ‘c’; }
};
int main() {
try{
Botch b;
b.f();
} catch(…) {
cout << "inside catch(…)" << endl;
}
} ///:~
The class Botch not only throws an exception inside f(), but also in
its destructor. This is one of the situations that causes a call to
terminate(), as you can see in main(). Even though the exception handler
says catch(…), which would seem to catch everything and leave no
cause for terminate() to be called, terminate() is called anyway, because
in the process of cleaning up the objects on the stack to handle one
exception, the Botch destructor is called, and that generates a second
exception, forcing a call to terminate(). Thus, a destructor that throws an
exception or causes one to be thrown is a design error.
Standard Exceptions
The set of exceptions used with the Standard C++ library are also
available for your own use. Generally it’s easier and faster to start with a
standard exception class than to try to define your own. If the standard
class doesn’t do what you need, you can derive from it.
The base class for all the exceptions thrown by the C++
exception standard library. You can ask what() and get a result that
can be displayed as a character representation.
logic_error Derived from exception. Reports program logic errors,
which could presumably be detected before the program
executes.
runtime_erro Derived from exception. Reports runtime errors, which can
r presumably be detected only when the program executes.
The classes in both of the following tables can be used as they are,
or they can act as base classes to derive your own more specific types of
exceptions.
Ans –
A)Containers
B)Iterators
While loop
{
Statement1;
Statement 2;
}
In the above example, condition expression is evaluated and if the
condition is true, then the statement1 and statement2 is executed.
After execution, the condition is checked again. If true, the
statements inside the while loop are executed again. This continues
until the loop condition becomes false. Hence the variable used in the
loop condition should be modified inside the loop so that the loop
termination condition is reached. Otherwise the loop will be executed
infinitely and the program will hang when executed. Also the loop
variable should be iniatialised to avoid the variable taking junk value
and create bugs in the program.
C) Algorithms
Ans –
A)Instance Diagram
instanceName: datatype
You can choose to name the instance or not, but the datatype
should always be specified. Below the name, you can also list the
attributes and their values. In Visual Case, you can map attributes from
your class and enter new values specific to that instance. Attributes need
only be shown when they are important and you don’t have to specify
and show all of the attributes of a class.
B)Sequence Diagram
· The flow of time is shown from top to bottom, that is messages higher
on the diagram happen before those lower down
· The blue boxes are instances of the represented classes, and the
vertical bars below are timelines
· The arrows (links) are messages – operation calls and returns from
operations
· The hide and show messages use guards to determine which to call.
Guards are always shown in square braces [ ] and represent constraints
on the message (the message is sent only if the constraint is satisfied)
· The messages are labeled with the operation being called and
parameters are shown. You can choose to enter the parameters or not –
this is dependent upon their importance to the collaboration being shown
Asynchronous Messages
C)Collaboration Diagram
Lollipop Interfaces