21-22 Solution
21-22 Solution
21-22 Solution
Association
Yes you can inherit abstract class from another abstract class. Yes you can inherit or extend
one abstract class to another abstract class but if the class is a sealed class or single ton class
at that time only inheritance cant’ be applicable
The protected access specifier allows the class the member belongs to, friends, and derived classes to
access the member. However, protected members are not accessible from outside the class.
5. When will you make a function name inline? Why?
We will make a function inline when the functions are small that called often. Inline functions
run a little faster than the normal functions as the compiler replaces the function call
statement with the function code itself and then compiles the entire code.
Destructors are usually used to deallocate memory and do other cleanup for a class object and
its class members when the object is destroyed. A destructor is called for a class object when that
object passes out of scope or is explicitly deleted.
Section B
II. Attempt any three part of the following:
a) What is constructor ? Write down the different
characteristics of a constructor. Write a program
in C++ for constructor overloading.
A constructor can be defined as a special member function which is used to initialize the objects
of the class with initial values. It is special member function as its name is the same as the class
name. It enables an object to initialize itself during its creation. This is termed as automatic
initialization of objects.
Features of constructors:
Constructor have following special features:
1. A constructor name must be same as that of its class name.
2. Constructors are called automatically when the objects are created.
3. Constructors should be declared in the public section to be availabile to all the
functions.
4. Constructors do not have return type , not even void and therefore they can not return
value.
5. Constructors can have default arguments as other C++ functions.
6. Constructors can not be inherited.
7. Constructors can not be static.
8. Constructors can not be virtual.
9. The address of a constructor can not be referred.
10. Constructors are member functions so they can be overloaded.
• class Person {
• private:
• int age;
•
• public:
• // 1. Constructor with no arguments
• Person() {
• age = 20;
• }
•
• // 2. Constructor with an argument
• Person(int a) {
• age = a;
• }
•
• int getAge() {
• return age;
• }
• };
•
• int main() {
• Person person1, person2(45);
•
• cout << "Person1 Age = " << person1.getAge() << endl;
• cout << "Person2 Age = " << person2.getAge() << endl;
•
• return 0;
• }
When an instruction of a function call is encountered during the compilation of a program, its
memory address is stored by the compiler. The function arguments are copied on the stack
and after the execution of the code, the control is transferred to the calling instruction. This
process can sometimes cause overhead in function calls, especially if the function is small
and its execution time is less than the switching time. This issue is resolved by using the
inline functions. These functions overcome the overhead and also make the program faster by
reducing the execution time of the program.
In case of inline functions, the compiler does not go through the above process of switching
between the stack and calling function. Instead, it copies the definition of the inline function
and the calling instruction with that definition. The following demonstration illustrates the
working of inline function in C++:
int main() {
// call the inline function
// first call
printSum(10, 20);
// second call
printSum(2, 5);
// third call
printSum(100, 400);
return 0;
Following are some key points that you need to keep in mind while dealing with inline
functions:
• Inline functions that are small have higher efficiency and better results than the lengthier
inline functions. So, try to keep your inline functions small in length.
• Although these functions increase the efficiency of the program and improve its
execution, you should not convert all the functions into inline functions. If you convert
larger functions to inline, it may lead to code bloat and reduce the functioning quality of
the program.
• Always try to define large functions outside the class, since functions defined inside a
class are automatically defined as inline and this will affect the program negatively. You
can use scope resolution (::) for this purpose.
A class, on the other hand, is a blueprint of the object. Conversely, an object can be defined as an
instance of a class. A class contains a skeleton of the object and does not take any space in the
memory.
Let us take an Example of a car object. A car object named “Maruti” can have data such as color;
make, model, speed limit, etc. and functions like accelerate. We define another object “ford”.
This can have similar data and functions like that of the previous object plus some more
additions.
Similarly, we can have numerous objects of different names having similar data and functions
and some minor variations.
Thus instead of defining these similar data and functions in these different objects, we define a
blueprint of these objects which is a class called Car. Each of the objects above will be instances
of this class car.
Abstraction
Abstraction is the process of hiding irrelevant information from the user. For Example, when we
are driving the car, first we start the engine by inserting a key. We are not aware of the process
that goes on in the background for starting the engine.
Using abstraction in programming, we can hide unnecessary details from the user. By using
abstraction in our application, the end user is not affected even if we change the internal
implementation.
Encapsulation
Encapsulation is the process using which data and the methods or functions operating on them are
bundled together. By doing this, data is not easily accessible to the outside world. In OOP we
achieve encapsulation by making data members as private and having public functions to access
these data members.
Inheritance
Using inheritance object of one class can inherit or acquire the properties of the object of another
class. Inheritance provides reusability of code.
As such we can design a new class by acquiring the properties and functionality of another class
and in this process, we need not modify the functionality of the parent class. We only add new
functionality to the class.
Polymorphism
Polymorphism means many forms.
Polymorphism is an important feature of OOP and is usually implemented as operator
overloading or function overloading. Operator overloading is a process in which an operator
behaves differently in different situations. Similarly, in function overloading, the same function
behaves differently in different situations.
Dynamic Binding
OOP supports dynamic binding in which function call is resolved at runtime. This means that the
code to be executed as a result of a function call is decided at runtime. Virtual functions are an
example of dynamic binding.
Message Passing
In OOP, objects communicate with each other using messages. When objects communicate,
information is passed back and forth between the objects. A message generally consists of the
object name, method name and actual data that is to be sent to another object.
Advantages Of OOP
#1) Reusability
OOP allows the existing code to be reused through inheritance. We can easily acquire the existing
functionality and improve on it without having to rewrite the code again. This results in less
bloated code.
#2) Modularity
As we modularize the program in OOP, it’s easy to modify or troubleshoot the program if a
problem occurs or new feature or enhancement is to be added. Modularization also helps in code
clarity and makes it more readable.
#3) Flexibility
OOP helps us with flexible programming using the polymorphism feature. As polymorphism
takes many forms, we can have operators or functions that will work with many objects and thus
save us from writing different functions for each object.
#4) Maintainability
Maintaining code is easier as it is easy to add new classes, objects, etc without much restructuring
or changes.
#include <iostream>
using namespace std;
bool check_prime(int);
int main() {
int n;
cout << "Enter a positive integer: ";
cin >> n;
if (check_prime(n))
cout << n << " is a prime number.";
else
cout << n << " is not a prime number.";
return 0;
}
bool check_prime(int n) {
bool is_prime = true;
return is_prime;
}
During inheritance, the data members of the base class get copied in the derived class and can
be accessed depending upon the visibility mode used. The order of the accessibility is always
in a decreasing order i.e., from public to protected. There are mainly five types of Inheritance
in C++ that you will explore in this article. They are as follows:
• Single Inheritance
• Multiple Inheritance
• Multilevel Inheritance
• Hierarchical Inheritance
• Hybrid Inheritance
• #include <iostream>
• using namespace std;
•
• // create a base class1
• class Base_class
• {
• // access specifier
• public:
• // It is a member function
• void display()
• {
• cout << " It is the first function of the Base class " << endl;
• }
• };
•
• // create a base class2
• class Base_class2
• {
• // access specifier
• public:
• // It is a member function
• void display2()
• {
• cout << " It is the second function of the Base class " << endl;
• }
• };
•
• /* create a child_class to inherit features of Base_class and Base_class2 with access s
pecifier. */
• class child_class: public Base_class, public Base_class2
• {
•
• // access specifier
• public:
• void display3() // It is a member function of derive class
• {
• cout << " It is the function of the derived class " << endl;
• }
•
• };
•
• int main ()
• {
• // create an object for derived class
• child_class ch;
• ch.display(); // call member function of Base_class1
• ch.display2(); // call member function of Base_class2
• ch.display3(); // call member function of child_class
• }
Section C
III. Attempt any one part of the following:
a) What is polymorphism? Differentiate between
runtime polymorphism and compile time
polymorphism.
• Polymorphism is one of the most important OOPs concepts. Its is a concept by which
we can perform single task in multiple ways. There are two types of polymorphism one
is Compile-time polymorphism and another is run-time polymorphism.
• Method overloading is the example of compile time polymorphism and method
overriding is the example of run-time polymorphism.
•
• Multiplicity in the reverse direction
• Here we had to place the lower and upper bound on the other end, and consequently,
we must now read from right to left:
• One bank account must belong to one up to two customers*.
• Again, the diagram does not contain the cardinality of "one" for the bank account.
•
Finally, we can combine both multiplicities into the same diagram to express both
directions:
•
• Both multiplicities combined in a single diagram
• It's essential to keep in mind that this diagram combines the two expressions
mentioned above into a single diagram, so the correct way to read it would be:
• One customer has one to five bank accounts and one bank account belongs to one or
two customers.
• and not, as one would intuitively think
• One or two customers have one to five bank accounts.
• Multiplicity in UMLBoard
• 1.4
• UMLBoard supports the definition of multiplicities for all associations (i.e.,
compositions, aggregations, and simple associations). By default, a newly created
relationship does not have any multiplicity information stored, indicated by the
grayed-out text none when moving the mouse over a connection.
•
• A connection in UMLBoard without any multiplicity set
• Start Editing
• To add a multiplicity to a connection, click and hold (or double-click) on one of
the none texts. The cardinality editor will open with the cursor always starting on the
edit field for the lower bound.
•
• The cardinality editor can be opened by clicking on a multiplicity
• Just enter any cardinality you want; UMLBoard does not set you any restrictions here.
You can use any number or arbitrary string as input. If you only want to set a single
boundary, you can also leave one cardinality edit field empty. Clearing both edit
fields will remove the multiplicity from this end.
UML describes the real-time systems, it is very important to make a conceptual model and then
proceed gradually. The conceptual model of UML can be mastered by learning the following
three major elements −
• Things
• Relationships
• Diagrams
Things
Things are the most important building blocks of UML. Things can be −
• Structural
• Behavioral
• Grouping
• Annotational
Structural Things
Structural things define the static part of the model. They represent the physical and
conceptual elements. Following are the brief descriptions of the structural things.
Class − Class represents a set of objects having similar responsibilities.
Interface − Interface defines a set of operations, which specify the responsibility of a class.
Node − A node can be defined as a physical element that exists at run time.
Behavioral Things
A behavioral thing consists of the dynamic parts of UML models. Following are the
behavioral things −
Interaction − Interaction is defined as a behavior that consists of a group of messages
exchanged among elements to accomplish a specific task.
State machine − State machine is useful when the state of an object in its life cycle is
important. It defines the sequence of states an object goes through in response to events. Events
are external factors responsible for state change
Grouping Things
Grouping things can be defined as a mechanism to group elements of a UML model together.
There is only one grouping thing available −
Package − Package is the only one grouping thing available for gathering structural and
behavioral things.
Annotational Things
Annotational things can be defined as a mechanism to capture remarks, descriptions, and
comments of UML model elements. Note - It is the only one Annotational thing available. A
note is used to render comments, constraints, etc. of an UML element.
Relationship
Relationship is another most important building block of UML. It shows how the elements are
associated with each other and this association describes the functionality of an application.
There are four kinds of relationships available.
Dependency
Dependency is a relationship between two things in which change in one element also affects
the other.
Association
Association is basically a set of links that connects the elements of a UML model. It also
describes how many objects are taking part in that relationship.
Generalization
Generalization can be defined as a relationship which connects a specialized element with a
generalized element. It basically describes the inheritance relationship in the world of objects.
Realization
Realization can be defined as a relationship in which two elements are connected. One element
describes some responsibility, which is not implemented and the other one implements them.
This relationship exists in case of interfaces.
UML Diagrams
UML diagrams are the ultimate output of the entire discussion. All the elements, relationships
are used to make a complete UML diagram and the diagram represents a system.
The visual effect of the UML diagram is the most important part of the entire process. All the
other elements are used to make it complete.
UML includes the following nine diagrams, the details of which are described in the subsequent
chapters.
• Class diagram
• Object diagram
• Use case diagram
• Sequence diagram
• Collaboration diagram
• Activity diagram
• Statechart diagram
• Deployment diagram
• Component diagram
• Seven Types of Structural Things
5. Active Class - Like a class but its represents behavior that runs
concurrent with other behaviors, i.e. threading.
When there is more than one data type present in an expression, there is a possibility of data
loss because different data types are not compatible with each other. Data loss occurs if a
variable converts from a higher data type to a lower data type. In order to avoid data loss, the
compiler automatically converts all the data types to the highest data type present in the
expression. This is called promotion. The precedence of different data types is given below.
For example:
#include <iostream>
using namespace std;
int main() {
int int_var;
float float_var = 20.5;
int_var = float_var;
// trying to store the value of float_var in int_var
cout << "The value of int_var is: " << int_var << endl;
cout << "The value of float_var is: " << float_var << endl;
return 0;
}
Output:
When a float is converted to int, the numbers after the decimal point are lost. This is why the
value 20.5 was converted to 20 when we tried to store a float value in an int variable.
Similarly, when a signed int is implicitly converted to an unsigned int, the sign of the integer
is lost.
The following is the correct order of automatic type conversion from lower rank of data type
to higher rank of data type.
#include <iostream>
using namespace std;
int main() {
int int_var = 50;
char char_var = 'a';
cout << "The value of (50 + 'a') is: " << int_var << endl;
cout << "The value of float_var is: " << float_var << endl;
return 0;
}
Output:
Explicit typecasting using the assignment operator is also referred to as forced casting. This
conversion is done by explicitly declaring the required data type in front of the expression. It
can be done in two ways:
This type casting is usually used in the C programming language. It is also known as cast
notation. The syntax for this casting is:
(datatype)expression;
For example:
#include <iostream>
using namespace std;
int main() {
char char_var = 'a';
int int_var;
cout << "The value of char_var is: " << char_var << endl;
cout << "The value of int_var is: " << int_var << endl;
return 0;
}
Output:
In this example, we explicitly converted a char variable into an int. The result being, the
character 'a' was converted to 97.
As the name suggests, we can perform explicit typecasting using function style notations. It is
also known as old C++ style type casting. The syntax for this casting is:
datatype(expression);
For example:
#include <iostream>
using namespace std;
int main() {
int int_var = 17;
float float_var;
float_var = float(int_var) / 2;
// explicitly converting an int to a float
cout << "The value of float_var is: " << float_var << endl;
return 0;
}
Output:
Let's have a look at its example of a class vegetable. The vegetable class has two objects, i.e.,
onion and eggplant. According to the reflexive association's definition, the link between the
onion and eggplant exist, as they belong to the same class, i.e., vegetable.
Directed Association
The directed association is concerned with the direction of flow inside association classes.
The flow of association can be shown by employing a directed association. The directed
association between two classes is represented by a line with an arrowhead, which indicates
the navigation direction. The flow of association from one class to another is always in one
direction.
It can be said that there is an association between a person and the company. The
person works for the company. Here the person works for the company, and not
the company works for a person.
Figure 1: Aggregation
The employee and address are linked with the “has a” relationship. An instance of the Address
class can exist without an instance of the Employee. It is an aggregation. In UML, the diamond
symbol represents an aggregation. The direction denotes which object contains the other object.
Figure 2: Generalization
Employee is the superclass. Permanent and Temporary Employee are subclasses whereas
Employee is the generalized form of Permanent and Temporary Employee. On the other hand,
Permanent and Temporary Employee are specialized forms of Employee. Employee has
properties id, name, salary and the method display. The subclasses Permanent and Temporary
Employee can also use these properties and methods. Furthermore, the subclasses have their
own properties and methods. In UML, an arrow represents generalization.
Relationship
Aggregation denotes “has a” relationship while Generalization denotes “is a” relationship.
UML representation
A diamond symbol represents an aggregation whereas an arrow symbol represents
generalization. Hence, this further explains the difference between aggregation and
generalization in UML.
By using the keyword friend compiler knows the given function is a friend function.
For accessing the data, the declaration of a friend function should be done inside the body of
a class starting with the keyword friend.
In the above declaration, the friend function is preceded by the keyword friend. The function
can be defined anywhere in the program like a normal C++ function. The function definition
does not use either the keyword friend or scope resolution operator.
o The function is not in the scope of the class to which it has been declared as a friend.
o It cannot be called using the object as it is not in the scope of that class.
o It can be invoked like a normal function without using the object.
o It cannot access the member names directly and has to use an object name and dot
membership operator with the member name.
o It can be declared either in the private or the public part.
C++ friend function Example
Let's see the simple example of C++ friend function used to print the length of a box.
1. #include <iostream>
2. using namespace std;
3. class Box
4. {
5. private:
6. int length;
7. public:
8. Box(): length(0) { }
9. friend int printLength(Box); //friend function
10. };
11. int printLength(Box b)
12. {
13. b.length += 10;
14. return b.length;
15. }
16. int main()
17. {
18. Box b;
19. cout<<"Length of box: "<< printLength(b)<<endl;
20. return 0;
21. }
Output:
Length of box: 10
Let's see a simple example when the function is friendly to two classes.
1. #include <iostream>
2. using namespace std;
3. class B; // forward declarartion.
4. class A
5. {
6. int x;
7. public:
8. void setdata(int i)
9. {
10. x=i;
11. }
12. friend void min(A,B); // friend function.
13. };
14. class B
15. {
16. int y;
17. public:
18. void setdata(int i)
19. {
20. y=i;
21. }
22. friend void min(A,B); // friend function
23. };
24. void min(A a,B b)
25. {
26. if(a.x<=b.y)
27. std::cout << a.x << std::endl;
28. else
29. std::cout << b.y << std::endl;
30. }
31. int main()
32. {
33. A a;
34. B b;
35. a.setdata(10);
36. b.setdata(20);
37. min(a,b);
38. return 0;
39. }
Output:
10
In the above example, min() function is friendly to two classes, i.e., the min() function can
access the private members of both the classes A and B.
b) Explain the following concepts in C++ by taking
a suitable example:
1) This pointer
2) Array of objects
This pointer
• Every object in C++ has access to its own address through an important pointer
called this pointer. The this pointer is an implicit parameter to all member functions.
Therefore, inside a member function, this may be used to refer to the invoking object.
• Friend functions do not have a this pointer, because friends are not members of a class.
Only member functions have a this pointer.
• Let us try the following example to understand the concept of this pointer −
• Live Demo
• #include <iostream>
•
• using namespace std;
•
• class Box {
• public:
• // Constructor definition
• Box(double l = 2.0, double b = 2.0, double h = 2.0) {
• cout <<"Constructor called." << endl;
• length = l;
• breadth = b;
• height = h;
• }
• double Volume() {
• return length * breadth * height;
• }
• int compare(Box box) {
• return this->Volume() > box.Volume();
• }
•
• private:
• double length; // Length of a box
• double breadth; // Breadth of a box
• double height; // Height of a box
• };
•
• int main(void) {
• Box Box1(3.3, 1.2, 1.5); // Declare box1
• Box Box2(8.5, 6.0, 2.0); // Declare box2
•
• if(Box1.compare(Box2)) {
• cout << "Box2 is smaller than Box1" <<endl;
• } else {
• cout << "Box2 is equal to or larger than Box1" <<endl;
• }
•
• return 0;
• }
•
Array of objects
suppose we have 50 students in a class and we have to input the name and marks of all the 50
students. Then creating 50 different objects and then inputting the name and marks of all
those 50 students is not a good option. In that case, we will create an array of objects as we
do in case of other data-types.
Let's see an example of taking the input of name and marks of 5 students by creating an array
of the objects of students.
#include <iostream>
#include <string>
class Student
{
string name;
int marks;
public:
void getName()
{
getline( cin, name );
}
void getMarks()
{
cin >> marks;
}
void displayInfo()
{
cout << "Name : " << name << endl;
cout << "Marks : " << marks << endl;
}
};
int main()
{
Student st[5];
for( int i=0; i<5; i++ )
{
cout << "Student " << i + 1 << endl;
cout << "Enter name" << endl;
st[i].getName();
cout << "Enter marks" << endl;
st[i].getMarks();
}
Output
Now let’s go through this code.
Student st[5]; - We created an array of 5 objects of the Student class where each object
represents a student having a name and marks.
The first for loop is for taking the input of name and marks of the
students. getName() and getMarks() are the functions to take the input of name and marks
respectively.
The second for loop is to print the name and marks of all the 5 students. For that, we called
the displayInfo() function for each student.