Unit 1
Foundation of Object Oriented Programming
Introduction to Procedural
In the procedure-oriented approach, the problem is viewed as the sequence of things to be done such as reading, calculating and printing such as cobol, fortran and c. The primary focus is on functions. A typical structure for procedural programming is shown. The technique of hierarchical decomposition has been used to specify the tasks to be completed for solving a problem.
Procedure oriented programming basically consists of writing a list of instructions for the computer to follow, and organizing these instructions into groups known as functions. We normally use flowcharts to organize these actions and represent the flow of control from one action to another.
In a multi-function program, many important data items are placed as global so that they may be accessed by all the functions. Each function may have its own local data. Global data are more vulnerable to an inadvertent change by a function. In a large program it is very difficult to identify what data is used by which function. In case we need to revise an external data structure, we also need to revise all functions that access the data. This provides an opportunity for bugs to creep in.
Another serious drawback with the procedural approach is that we do not model real world problems very well. This is because functions are action-oriented and do not really corresponding to the element of the problem.
Some Characteristics exhibited by procedure-oriented programming are: • Emphasis is on doing things (algorithms).
• Large programs are divided into smaller programs known as functions.
• Most of the functions share global data.
• Data move openly around the system from function to function.
• Functions transform data from one form to another.
• Employs top-down approach in program design.
Modular
Principles of Object-Oriented Systems
The conceptual framework of object–oriented systems is based upon the object model. There are two categories of elements in an object-oriented system −
Major Elements − By major, it is meant that if a model does not have any one of these elements, it ceases to be object oriented. The four major elements are −
- Abstraction
- Encapsulation
- Modularity
- Hierarchy
Minor Elements − By minor, it is meant that these elements are useful, but not indispensable part of the object model. The three minor elements are −
- Typing
- Concurrency
- Persistence
Abstraction
Abstraction means to focus on the essential features of an element or object in OOP, ignoring its extraneous or accidental properties. The essential features are relative to the context in which the object is being used.
Grady Booch has defined abstraction as follows −
“An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of objects and thus provide crisply defined conceptual boundaries, relative to the perspective of the viewer.”
Example − When a class Student is designed, the attributes enrolment number, name, course, and address are included while characteristics like pulse_rate and size_of_shoe are eliminated, since they are irrelevant in the perspective of the educational institution.
Encapsulation
Encapsulation is the process of binding both attributes and methods together within a class. Through encapsulation, the internal details of a class can be hidden from outside. The class has methods that provide user interfaces by which the services provided by the class may be used.
Modularity
Modularity is the process of decomposing a problem (program) into a set of modules so as to reduce the overall complexity of the problem. Booch has defined modularity as −
“Modularity is the property of a system that has been decomposed into a set of cohesive and loosely coupled modules.”
Modularity is intrinsically linked with encapsulation. Modularity can be visualized as a way of mapping encapsulated abstractions into real, physical modules having high cohesion within the modules and their inter–module interaction or coupling is low.
Hierarchy
In Grady Booch’s words, “Hierarchy is the ranking or ordering of abstraction”. Through hierarchy, a system can be made up of interrelated subsystems, which can have their own subsystems and so on until the smallest level components are reached. It uses the principle of “divide and conquer”. Hierarchy allows code reusability.
The two types of hierarchies in OOA are −
- “IS–A” hierarchy − It defines the hierarchical relationship in inheritance, whereby from a super-class, a number of subclasses may be derived which may again have subclasses and so on. For example, if we derive a class Rose from a class Flower, we can say that a rose “is–a” flower.
- “PART–OF” hierarchy − It defines the hierarchical relationship in aggregation by which a class may be composed of other classes. For example, a flower is composed of sepals, petals, stamens, and carpel. It can be said that a petal is a “part–of” flower.
Typing
According to the theories of abstract data type, a type is a characterization of a set of elements. In OOP, a class is visualized as a type having properties distinct from any other types. Typing is the enforcement of the notion that an object is an instance of a single class or type. It also enforces that objects of different types may not be generally interchanged; and can be interchanged only in a very restricted manner if absolutely required to do so.
The two types of typing are −
- Strong Typing − Here, the operation on an object is checked at the time of compilation, as in the programming language Eiffel.
- Weak Typing − Here, messages may be sent to any class. The operation is checked only at the time of execution, as in the programming language Smalltalk.
Concurrency
Concurrency in operating systems allows performing multiple tasks or processes simultaneously. When a single process exists in a system, it is said that there is a single thread of control. However, most systems have multiple threads, some active, some waiting for CPU, some suspended, and some terminated. Systems with multiple CPUs inherently permit concurrent threads of control; but systems running on a single CPU use appropriate algorithms to give equitable CPU time to the threads so as to enable concurrency.
In an object-oriented environment, there are active and inactive objects. The active objects have independent threads of control that can execute concurrently with threads of other objects. The active objects synchronize with one another as well as with purely sequential objects.
Persistence
An object occupies a memory space and exists for a particular period of time. In traditional programming, the lifespan of an object was typically the lifespan of the execution of the program that created it. In files or databases, the object lifespan is longer than the duration of the process creating the object. This property by which an object continues to exist even after its creator ceases to exist is known as persistence.
Objects-Oriented and Generic Programming Techniques
Object-oriented programming
Object-oriented programming is based on the three concepts encapsulation, inheritance, and polymorphism.
Encapsulation
An object encapsulates its attributes and methods and provides them via an interface to the outside world. This property that an object hides its implementation is often called data hiding.
Inheritance
A derived class get all characteristics from its base class. You can use an instance of a derived class as an instance of its base class. We often speak about code reuse because the derived class automatically gets all characteristics of the base class .
Polymorphism
Polymorphism is the ability to present the same interface for differing underlying data types. The term is from Greek and stands for many forms.
1 2 3 4 5 6 7 8 9 10 11 12 13 | Class HumanBeing{ Public: HumanBeing(std::stringn):name(n){} Virtual std::string getName() const{ Return name; } Private: Std::string name; };
Class Man: public HumanBeing{};
Class Woman: public HumanBeing{}; |
In the example you only get the name of HumanBeing by using the method getName in line 4 (encapsulation). In addition, getName is declared as virtual. Therefore, derived classes can change the behaviour of their methods and therefore change the behaviour of their objects (polymorphism). Man and Woman are derived from HumanBeing.
Generic programming
The key idea of generic programming or programming with templates is to define families of functions or classes. By providing the concrete type you get automatically a function or a class for this type. Generic programming provides similar abstraction like object-oriented programming. A big difference is that polymorphism of object-oriented programming will happen at runtime; that polymorphism of generic programming will happen in C++ at compile time. That the reason why polymorphism at runtime is often called dynamic polymorphism but polymorphism at compile is often called static polymorphism.
By using the function template I can exchange arbitrary objects.
1 2 3 4 5 6 7 8 9 10 11 12 | Template <typename T> void xchg(T& x, T& y){ T t= x; x= y; y= t; }; Int i= 10; Int j= 20; Man huber; Man maier;
Xchg(i,j); Xchg(huber,maier); |
It doesn't matter for the function template, if I exchange numbers or men (line 11 and 12). In addition, I have not to specify the type parameter (line) because the compiler can derived it from the function arguments (line 11 and 12).
The automatic type deduction of function templates will not hold for class templates. In the concrete case I have to specify the type parameter T and the non-type parameter N (line 1).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Template <typename T, int N> Class Array{ Public: Int getSize() const{ Return N; } Private: T elem[N]; };
Array<double,10> doubleArray; Std::cout << doubleArray.getSize() << std::endl;
Array<Man,5> manArray; Std::cout << manArray.getSize() << std::endl; |
Accordingly, the application of the class template Array is independent of the fact, whether I use doubles or men.
Functional programming
A will only say a few words about functional programming because I will and can not explain the concept of functional programming in a short remark. Only that much. I use the code snippet the pendants in C++ to the typical functions in functional programming: map, filter, and reduce. These are the functions std::transform, std::remove_if, and std::accumulate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Std::vector<int> vec{1,2,3,4,5,6,7,8,9}; Std::vector<std::string> str{"Programming","in","a","functional","style."};
Std::transform(vec.begin(),vec.end(),vec.begin(), [](int i){ return i*i; }); // {1,4,9,16,25,36,49,64,81}
Auto it= std::remove_if(vec.begin(),vec.end(), [](int i){ return ((i < 3) or (i > 8)) }); // {3,4,5,6,7,8} Auto it2= std::remove_if(str.begin(),str.end(), [](string s){ return (std::lower(s[0])); }); // "Programming"
Std::accumulate(vec.begin(),vec.end(),[](int a,int b){return a*b;}); // 362880 Std::accumulate(str.begin(),str.end(), [](std::string a,std::string b){return a + ":"+ b;}); // "Programming:in:a:functional:style." |
I apply in the code snippet two powerful features of functional programming. Both are now mainstream in modern C++: automatic type deduction with auto and lambda-functions.
KEY TAKEAWAY
In the procedure oriented approach, the problem is viewed as the sequence of things to be done such as reading, calculating and printing such as COBOL, FORTRAN and c. The primary focus is on functions.
The conceptual framework of object–oriented systems is based upon the object model. There are two categories of elements in an object-oriented system −
Major Elements − By major, it is meant that if a model does not have any one of these elements, it ceases to be object oriented. The four major elements are −
- Abstraction
- Encapsulation
- Modularity
- Hierarchy
Minor Elements − By minor, it is meant that these elements are useful, but not indispensable part of the object model. The three minor elements are −
- Typing
- Concurrency
- Persistence
Object-oriented programming is based on the three concepts encapsulation, inheritance, and polymorphism.
The key idea of generic programming or programming with templates is to define families of functions or classes.
- Well, although procedural-oriented programs are extremely powerful, they do have some limitations.
- Perhaps the most serious limitation is the tendency for large procedural-based programs to turn into "spaghetti-code".
- Spaghetti code is code that has been modified so many times that the logical flow shown in the figures above becomes so convoluted that any new programmer coming onto the project needs a two month prep-course in order to even begin to understand the software innards.
- Why does this happen?
- Well, in reality, a programmer's job has just begun when she finishes writing version 1.0 of her software application. Before she knows it, she'll be bombarded with dozens of modification requests and bug reports as users actually get to batter and bruise her poor piece of code.
- In order to meet the demands of the evil user, the programmer is forced to modify the code. This can mean introducing new sub loops, new eddies of flow control and new methods, libraries and variables altogether.
- Unfortunately, there are no great tools for abstraction and modularization in procedural languages...thus, it is hard to add new functionality or change the work flow without going back and modifying all other parts of the program.
- Now, instead of redesigning the workflow and starting from scratch, most programmers, under intense time restrictions will introduce hacks to fix the code.
- This gets us to the second problem with procedural-based programming. Not only does procedural code have a tendency to be difficult to understand, as it evolves, it becomes even harder to understand, and thus, harder to modify.
- Since everything is tied to everything else, nothing is independent. If you change one bit of code in a procedural-based program, it is likely that you will break three other pieces in some other section that might be stored in some remote library file you'd forgotten all about.
- A final problem with spaghetification is that the code you write today will not help you write the code you have to write tomorrow. Procedural-based code has a tenacious ability to resist being cut and pasted from one application to another. Thus, procedural programmers often find themselves reinventing the wheel on every new project.
KEY TAKEAWAY
- The most serious limitation is the tendency for large procedural-based programs to turn into "spaghetti-code".
- Spaghetti code is code that has been modified so many times that the logical flow shown in the figures above becomes so convoluted that any new programmer coming onto the project needs a two month prep-course in order to even begin to understand the software innards.
For Example: Consider the Class of Cars. There may be many cars with different names and brand but all of them will share some common properties like all of them will have 4 wheels, Speed Limit, Mileage range etc. So here, Car is the class and wheels, speed limits, mileage are their properties.
- A Class is a user-defined data-type which has data members and member functions.
- Data members are the data variables and member functions are the functions used to manipulate these variables and together these data members and member functions define the properties and behaviour of the objects in a Class.
- In the above example of class Car, the data member will be speed limit, mileage etc and member functions can apply brakes, increase speed etc.
We can say that a Class in C++ is a blue-print representing a group of objects which shares some common properties and behaviours.
Object: An Object is an identifiable entity with some characteristics and behaviour. An Object is an instance of a Class. When a class is defined, no memory is allocated but when it is instantiated (i.e. an object is created) memory is allocated.
Class person { Char name[20]; Int id; Public: Void getdetails(){} };
Int main() { Person p1; // p1 is a object } |
Object take up space in memory and have an associated address like a record in pascal or structure or union in C.
When a program is executed the objects interact by sending messages to one another.
Each object contains data and code to manipulate the data. Objects can interact without having to know details of each other’s data or code, it is sufficient to know the type of message accepted and type of response returned by the objects.
Encapsulation: In normal terms, Encapsulation is defined as wrapping up of data and information under a single unit. In Object-Oriented Programming, Encapsulation is defined as binding together the data and the functions that manipulate them.
Consider a real-life example of encapsulation, in a company, there are different sections like the accounts section, finance section, sales section etc. The finance section handles all the financial transactions and keeps records of all the data related to finance. Similarly, the sales section handles all the sales-related activities and keeps records of all the sales. Now there may arise a situation when for some reason an official from the finance section needs all the data about sales in a particular month. In this case, he is not allowed to directly access the data of the sales section. He will first have to contact some other officer in the sales section and then request him to give the particular data. This is what encapsulation is. Here the data of the sales section and the employees that can manipulate them are wrapped under a single name “sales section”.
Encapsulation in C++
Encapsulation also leads to data abstraction or hiding. As using encapsulation also hides the data. In the above example, the data of any of the section like sales, finance or accounts are hidden from any other section.
Abstraction: Data abstraction is one of the most essential and important features of object-oriented programming in C++. Abstraction means displaying only essential information and hiding the details. Data abstraction refers to providing only essential information about the data to the outside world, hiding the background details or implementation.
Consider a real-life example of a man driving a car. The man only knows that pressing the accelerators will increase the speed of the car or applying brakes will stop the car but he does not know about how on pressing accelerator the speed is actually increasing, he does not know about the inner mechanism of the car or the implementation of accelerator, brakes etc in the car. This is what abstraction is.
- Abstraction using Classes: We can implement Abstraction in C++ using classes. The class helps us to group data members and member functions using available access specifiers. A Class can decide which data member will be visible to the outside world and which is not.
- Abstraction in Header files: One more type of abstraction in C++ can be header files. For example, consider the pow() method present in math.h header file. Whenever we need to calculate the power of a number, we simply call the function pow() present in the math.h header file and pass the numbers as arguments without knowing the underlying algorithm according to which the function is actually calculating the power of numbers.
Polymorphism: The word polymorphism means having many forms. In simple words, we can define polymorphism as the ability of a message to be displayed in more than one form.
A person at the same time can have different characteristic. Like a man at the same time is a father, a husband, an employee. So the same person possesses different behaviour in different situations. This is called polymorphism.
An operation may exhibit different behaviours in different instances. The behaviour depends upon the types of data used in the operation.
C++ supports operator overloading and function overloading.
- Operator Overloading: The process of making an operator to exhibit different behaviours in different instances is known as operator overloading.
- Function Overloading: Function overloading is using a single function name to perform different types of tasks.
Polymorphism is extensively used in implementing inheritance.
Example: Suppose we have to write a function to add some integers, some times there are 2 integers, sometimes there are 3 integers. We can write the Addition Method with the same name having different parameters; the concerned method will be called according to parameters.
Inheritance: The capability of a class to derive properties and characteristics from another class is called Inheritance. Inheritance is one of the most important features of Object-Oriented Programming.
- Sub Class: The class that inherits properties from another class is called Sub class or Derived Class.
- Super Class: The class whose properties are inherited by sub class is called Base Class or Super class.
- Reusability: Inheritance supports the concept of “reusability”, i.e. when we want to create a new class and there is already a class that includes some of the code that we want, we can derive our new class from the existing class. By doing this, we are reusing the fields and methods of the existing class.
Example: Dog, Cat, Cow can be Derived Class of Animal Base Class.
Dynamic Binding: In dynamic binding, the code to be executed in response to function call is decided at runtime. C++ has virtual function to support this.
Message Passing: Objects communicate with one another by sending and receiving information to each other. A message for an object is a request for execution of a procedure and therefore will invoke a function in the receiving object that generates the desired results. Message passing involves specifying the name of the object, the name of the function and the information to be sent.
KEY TAKEAWAY
For Example: Consider the Class of Cars. There may be many cars with different names and brand but all of them will share some common properties like all of them will have 4 wheels, Speed Limit, Mileage range etc. So here, Car is the class and wheels, speed limits, mileage are their properties.
We can say that a Class in C++ is a blue-print representing a group of objects which shares some common properties and behaviours.
Objects
Objects are the basic run time entities in an object-oriented system. They may represent a person, a place, a bank account, a table of data or any item that the program has to handle. They may also represent user-defined data such as vectors, time and lists. Programming problem is analysed in term of objects and the nature of communication between them. Program objects should be chosen such that they match closely with the real-world objects. Objects take up space in the memory and have an associated address like a record in Pascal, or a structure in c.
When a program is executed, the objects interact by sending messages to one another. For example, if “customer” and “account” are to object in a program, then the customer object may send a message to the count object requesting for the bank balance. Each object contain data, and code to manipulate data. Objects can interact without having to know details of each other’s data or code. It is a sufficient to know the type of message accepted, and the type of response returned by the objects. Although different author represent them differently shows two notations that are popularly used in object-oriented analysis and design.
Classes
We just mentioned that objects contain data, and code to manipulate that data. The entire set of data and code of an object can be made a user-defined data type with the help of class. In fact, objects are variables of the type class. Once a class has been defined, we can create any number of objects belonging to that class. Each object is associated with the data of type class with which they are created. A class is thus a collection of objects similar types. For examples, Mango, Apple and orange members of class fruit. Classes are user-defined that types and behave like the built-in types of a programming language. The syntax used to create an object is not different then the syntax used to create an integer object in C. If fruit has been defines as a class, then the statement
Fruit Mango;
Will create an object mango belonging to the class fruit.
Data Members
"Data Member" and "Member Functions" are the new names/terms for the members of a class, which are introduced in C++ programming language.
The variables which are declared in any class by using any fundamental data types (like int, char, float etc) or derived data type (like class, structure, pointer etc.) are known as Data Members. And the functions which are declared either in private section of public section are known as Member functions.
There are two types of data members/member functions in C++:
- Private members
- Public members
1) Private members
The members which are declared in private section of the class (using private access modifier) are known as private members. Private members can also be accessible within the same class in which they are declared.
2) Public members
The members which are declared in public section of the class (using public access modifier) are known as public members. Public members can access within the class and outside of the class by using the object name of the class in which they are declared.
Consider the example:
Class Test
{
Private:
Int a;
Float b;
Char *name;
Void getA() { a=10; }
...;
Public:
Int count;
Void getB() { b=20; }
...;
};
Here, a, b, and name are the private data members and count is a public data member. While, getA() is a private member function and getB() is public member functions.
How to declare, define and access data members an member functions in a class?
#include <iostream>
#include <string.h>
Using namespace std;
#define MAX_CHAR 30
//class definition
Class person
{
//private data members
Private:
Char name [MAX_CHAR];
Int age;
//public member functions
Public:
//function to get name and age
Void get(char n[], int a)
{
Strcpy(name , n);
Age = a;
}
//function to print name and age
Void put()
{
Cout<< "Name: " << name <<endl;
Cout<< "Age: " <<age <<endl;
}
};
//main function
Int main()
{
//creating an object of person class
Person PER;
//calling member functions
PER.get("Manju Tomar", 23);
PER.put();
Return 0;
}
Output
Name: Manju Tomar
Age: 23
As we can see in the program, that private members are directly accessible within the member functions and member functions are accessible within in main() function (outside of the class) by using period (dot) operator like object_name.member_name;
Methods
A function is a group of statements that together perform a task. Every C++ program has at least one function, which is main(), and all the most trivial programs can define additional functions.
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is such that each function performs a specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
The C++ standard library provides numerous built-in functions that your program can call. For example, function strcat() to concatenate two strings, function memcpy() to copy one memory location to another location and many more functions.
A function is known with various names like a method or a sub-routine or a procedure etc.
Defining a Function
The general form of a C++ function definition is as follows −
Return_type function_name( parameter list ) {
Body of the function
}
A C++ function definition consists of a function header and a function body. Here are all the parts of a function −
- Return Type − A function may return a value. The return_type is the data type of the value the function returns. Some functions perform the desired operations without returning a value. In this case, the return_type is the keyword void.
- Function Name − This is the actual name of the function. The function name and the parameter list together constitute the function signature.
- Parameters − A parameter is like a placeholder. When a function is invoked, you pass a value to the parameter. This value is referred to as actual parameter or argument. The parameter list refers to the type, order, and number of the parameters of a function. Parameters are optional; that is, a function may contain no parameters.
- Function Body − The function body contains a collection of statements that define what the function does.
Example
Following is the source code for a function called max(). This function takes two parameters num1 and num2 and return the biggest of both −
// function returning the max between two numbers
Int max(int num1, int num2) {
// local variable declaration
Int result;
If (num1 > num2)
Result = num1;
Else
Result = num2;
Return result;
}
Function Declarations
A function declaration tells the compiler about a function name and how to call the function. The actual body of the function can be defined separately.
A function declaration has the following parts −
Return_type function_name( parameter list );
For the above defined function max(), following is the function declaration −
Int max(int num1, int num2);
Parameter names are not important in function declaration only their type is required, so following is also valid declaration −
Int max(int, int);
Function declaration is required when you define a function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
Calling a Function
While creating a C++ function, you give a definition of what the function has to do. To use a function, you will have to call or invoke that function.
When a program calls a function, program control is transferred to the called function. A called function performs defined task and when it’s return statement is executed or when its function-ending closing brace is reached, it returns program control back to the main program.
To call a function, you simply need to pass the required parameters along with function name, and if function returns a value, then you can store returned value. For example −
#include <iostream>
Using namespace std;
// function declaration
Int max(int num1, int num2);
Int main () {
// local variable declaration:
Int a = 100;
Int b = 200;
Int ret;
// calling a function to get max value.
Ret = max(a, b);
Cout << "Max value is : " << ret << endl;
Return 0;
}
// function returning the max between two numbers
Int max(int num1, int num2) {
// local variable declaration
Int result;
If (num1 > num2)
Result = num1;
Else
Result = num2;
Return result;
}
I kept max() function along with main() function and compiled the source code. While running final executable, it would produce the following result −
Max value is : 200
Function Arguments
If a function is to use arguments, it must declare variables that accept the values of the arguments. These variables are called the formal parameters of the function.
The formal parameters behave like other local variables inside the function and are created upon entry into the function and destroyed upon exit.
While calling a function, there are two ways that arguments can be passed to a function −
Sr.No | Call Type & Description |
1 | Call by Value This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument. |
2 | Call by Pointer This method copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument. |
3 | Call by Reference This method copies the reference of an argument into the formal parameter. Inside the function, the reference is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument. |
By default, C++ uses call by value to pass arguments. In general, this means that code within a function cannot alter the arguments used to call the function and above mentioned example while calling max() function used the same method.
Default Values for Parameters
When you define a function, you can specify a default value for each of the last parameters. This value will be used if the corresponding argument is left blank when calling to the function.
This is done by using the assignment operator and assigning values for the arguments in the function definition. If a value for that parameter is not passed when the function is called, the default given value is used, but if a value is specified, this default value is ignored and the passed value is used instead. Consider the following example −
#include <iostream>
Using namespace std;
Int sum(int a, int b = 20) {
Int result;
Result = a + b;
Return (result);
}
Int main () {
// local variable declaration:
Int a = 100;
Int b = 200;
Int result;
// calling a function to add the values.
Result = sum(a, b);
Cout << "Total value is :" << result << endl;
// calling a function again as follows.
Result = sum(a);
Cout << "Total value is :" << result << endl;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Total value is :300
Total value is :120
Messages
The messages standard facet is used to read individual strings from a message catalog.
The specifics on how messages are organized in a catalog depend on the library implementation.
The messages class template has a protected destructor: Programs shall only construct objects of derived classes, or use those installed in locale objects (through use_facet).
All standard locale objects support at least the following facet instantiations of the messages class template as part of the messages category:
Facets in locale objects | Description |
Messages<char> | Narrow characters |
Messages<wchar_t> | Wide characters |
Template parameters
CharT
Character type.
This is the type of characters for the returned messages.
Aliased as member char_type.
Member types
Member type | Definition | Description |
Char_type | The template parameter (charT) | Character type |
String_type | Basic_string<charT> | The basic_string instantiation for characters of type charT (such as string for char). |
The class also inherits the catalog type from messages_base. This type is a mere alias (typedef) of a signed integer type.
Member constants
The class contains a public static constant of type locale::id that uniquely identifies facets with money_put semantics.
Public member functions
(constructor)
Messages constructor (public member function)
Open
Open message catalog (public member function )
Get
Get message from catalog (public member function )
Close
Closse message catalog (public member function )
Virtual protected member functionss
The class defines the virtual protected members which implement the behavior by default of their respective public member functions:
Do_open
Open message catalog [virtual] (protected virtual member function )
Do_get
Get message from catalog [virtual] (protected virtual member function )
Do_close
Close message catalog (protected virtual member function )
Along with the class destructor:
(destructor)
Messages destructor (protected member function )
Specializations
At least the following specializations of this template are provided in all library implementations:
Specialization |
Messages<char> |
Messages<wchar_t> |
Data Encapsulation, Data Abstraction
Data Encapsulation
All C++ programs are composed of the following two fundamental elements −
- Program statements (code) − This is the part of a program that performs actions and they are called functions.
- Program data − The data is the information of the program which gets affected by the program functions.
Encapsulation is an Object Oriented Programming concept that binds together the data and functions that manipulate the data, and that keeps both safe from outside interference and misuse. Data encapsulation led to the important OOP concept of data hiding.
Data encapsulation is a mechanism of bundling the data, and the functions that use them and data abstraction is a mechanism of exposing only the interfaces and hiding the implementation details from the user.
C++ supports the properties of encapsulation and data hiding through the creation of user-defined types, called classes. We already have studied that a class can contain private, protected and public members. By default, all items defined in a class are private. For example −
Class Box {
Public:
Double getVolume(void) {
Return length * breadth * height;
}
Private:
Double length; // Length of a box
Double breadth; // Breadth of a box
Double height; // Height of a box
};
The variables length, breadth, and height are private. This means that they can be accessed only by other members of the Box class, and not by any other part of your program. This is one way encapsulation is achieved.
To make parts of a class public (i.e., accessible to other parts of your program), you must declare them after the public keyword. All variables or functions defined after the public specifier are accessible by all other functions in your program.
Making one class a friend of another exposes the implementation details and reduces encapsulation. The ideal is to keep as many of the details of each class hidden from all other classes as possible.
Data Encapsulation Example
Any C++ program where you implement a class with public and private members is an example of data encapsulation and data abstraction. Consider the following example −
#include <iostream>
Using namespace std;
Class Adder {
Public:
// constructor
Adder(int i = 0) {
Total = i;
}
// interface to outside world
Void addNum(int number) {
Total += number;
}
// interface to outside world
Int getTotal() {
Return total;
};
Private:
// hidden data from outside world
Int total;
};
Int main() {
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
Cout << "Total " << a.getTotal() <<endl;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Total 60
Above class adds numbers together, and returns the sum. The public members addNum and getTotal are the interfaces to the outside world and a user needs to know them to use the class. The private member total is something that is hidden from the outside world, but is needed for the class to operate properly.
Designing Strategy
Most of us have learnt to make class members private by default unless we really need to expose them. That's just good encapsulation.
This is applied most frequently to data members, but it applies equally to all members, including virtual functions.
Data Abstraction
Data abstraction refers to providing only essential information to the outside world and hiding their background details, i.e., to represent the needed information in program without presenting the details.
Data abstraction is a programming (and design) technique that relies on the separation of interface and implementation.
Let's take one real life example of a TV, which you can turn on and off, change the channel, adjust the volume, and add external components such as speakers, VCRs, and DVD players, BUT you do not know its internal details, that is, you do not know how it receives signals over the air or through a cable, how it translates them, and finally displays them on the screen.
Thus, we can say a television clearly separates its internal implementation from its external interface and you can play with its interfaces like the power button, channel changer, and volume control without having any knowledge of its internals.
In C++, classes provides great level of data abstraction. They provide sufficient public methods to the outside world to play with the functionality of the object and to manipulate object data, i.e., state without actually knowing how class has been implemented internally.
For example, your program can make a call to the sort() function without knowing what algorithm the function actually uses to sort the given values. In fact, the underlying implementation of the sorting functionality could change between releases of the library, and as long as the interface stays the same, your function call will still work.
In C++, we use classes to define our own abstract data types (ADT). You can use the cout object of class ostream to stream data to standard output like this −
#include <iostream>
Using namespace std;
Int main() {
Cout << "Hello C++" <<endl;
Return 0;
}
Here, you don't need to understand how cout displays the text on the user's screen. You need to only know the public interface and the underlying implementation of ‘cout’ is free to change.
Access Labels Enforce Abstraction
In C++, we use access labels to define the abstract interface to the class. A class may contain zero or more access labels −
- Members defined with a public label are accessible to all parts of the program. The data-abstraction view of a type is defined by its public members.
- Members defined with a private label are not accessible to code that uses the class. The private sections hide the implementation from code that uses the type.
There are no restrictions on how often an access label may appear. Each access label specifies the access level of the succeeding member definitions. The specified access level remains in effect until the next access label is encountered or the closing right brace of the class body is seen.
Benefits of Data Abstraction
Data abstraction provides two important advantages −
- Class internals are protected from inadvertent user-level errors, which might corrupt the state of the object.
- The class implementation may evolve over time in response to changing requirements or bug reports without requiring change in user-level code.
By defining data members only in the private section of the class, the class author is free to make changes in the data. If the implementation changes, only the class code needs to be examined to see what affect the change may have. If data is public, then any function that directly access the data members of the old representation might be broken.
Data Abstraction Example
Any C++ program where you implement a class with public and private members is an example of data abstraction. Consider the following example −
#include <iostream>
Using namespace std;
Class Adder {
Public:
// constructor
Adder(int i = 0) {
Total = i;
}
// interface to outside world
Void addNum(int number) {
Total += number;
}
// interface to outside world
Int getTotal() {
Return total;
};
Private:
// hidden data from outside world
Int total;
};
Int main() {
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
Cout << "Total " << a.getTotal() <<endl;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Total 60
Above class adds numbers together, and returns the sum. The public members - addNum and getTotal are the interfaces to the outside world and a user needs to know them to use the class. The private member total is something that the user doesn't need to know about, but is needed for the class to operate properly.
Designing Strategy
Abstraction separates code into interface and implementation. So while designing your component, you must keep interface independent of the implementation so that if you change underlying implementation then interface would remain intact.
In this case whatever programs are using these interfaces; they would not be impacted and would just need a recompilation with the latest implementation.
Information Hiding
Information hiding is a principle of OOP, where a stable interface is open to the rest of the program while its implementation details are hidden. This is usually achieved in OO languages (such as C++ and Java) by controlling access over the methods and fields of a class.
The problem is that C has only structs and their fields are always public, so the rest of the program always has access to the struct fields. This introduces the danger of higher coupling between modules, by directly manipulating the fields of a foreign data structure.
Fortunately, we can solve this by utilizing type forward declaration. For example, we can simulate an immutable class using the following structure:
// person.h
// Type forward declaration
// #include "person.h" provides that the type exists, but never shows the internal structure
Struct _person_t;
Typedef struct _person_t person_t;
// Simulates class constructor
Person_t *person_create(const char *name, unsigned int age);
// Simulates field getters
Const char *person_get_name(person_t *person);
Unsigned int person_get_age(person_t *person);
// Simulates class destructor
Void person_destroy(person_t *person);
// person.c
// By defining the internal structure here, we can prevent direct manipulation of
// the struct's fields.
Typedef struct _person_t {
Const char *name;
Unsigned int age;
} person_t;
Person_t *person_create(const char *name, unsigned int age) {
// Create and initialize an instance using malloc()
// Or, you can use any other custom strategy,
// e.g. For limiting memory usage or number of instances
Return new_person;
}
Const char *person_get_name(person_t *person) {
Return person->name;
}
Unsigned int person_get_age(person_t *person) {
Return person->age;
}
Void person_destroy(person_t *person) {
// Destroy the instance using free()
// Or, if you used an alternative strategy in person_create(), use custom cleanup routine here
}
Inheritance
In C++, inheritance is a process in which one object acquires all the properties and behaviors of its parent object automatically. In such way, you can reuse, extend or modify the attributes and behaviors which are defined in other class.
In C++, the class which inherits the members of another class is called derived class and the class whose members are inherited is called base class. The derived class is the specialized class for the base class.
Advantage of C++ Inheritance
Code reusability: Now you can reuse the members of your parent class. So, there is no need to define the member again. So less code is required in the class.
Types Of Inheritance
C++ supports five types of inheritance:
- Single inheritance
- Multiple inheritance
- Hierarchical inheritance
- Multilevel inheritance
- Hybrid inheritance
Derived Classes
A Derived class is defined as the class derived from the base class.
The Syntax of Derived class:
- Class derived_class_name :: visibility-mode base_class_name
- {
- // body of the derived class.
- }
Where,
Derived_class_name: It is the name of the derived class.
Visibility mode: The visibility mode specifies whether the features of the base class are publicly inherited or privately inherited. It can be public or private.
Base_class_name: It is the name of the base class.
- When the base class is privately inherited by the derived class, public members of the base class becomes the private members of the derived class. Therefore, the public members of the base class are not accessible by the objects of the derived class only by the member functions of the derived class.
- When the base class is publicly inherited by the derived class, public members of the base class also become the public members of the derived class. Therefore, the public members of the base class are accessible by the objects of the derived class as well as by the member functions of the base class.
Note:
- In C++, the default mode of visibility is private.
- The private members of the base class are never inherited.
C++ Single Inheritance
Single inheritance is defined as the inheritance in which a derived class is inherited from the only one base class.
Where 'A' is the base class, and 'B' is the derived class.
C++ Single Level Inheritance Example: Inheriting Fields
When one class inherits another class, it is known as single level inheritance. Let's see the example of single level inheritance which inherits the fields only.
- #include <iostream>
- Using namespace std;
- Class Account {
- Public:
- Float salary = 60000;
- };
- Class Programmer: public Account {
- Public:
- Float bonus = 5000;
- };
- Int main(void) {
- Programmer p1;
- Cout<<"Salary: "<<p1.salary<<endl;
- Cout<<"Bonus: "<<p1.bonus<<endl;
- Return 0;
- }
Output:
Salary: 60000
Bonus: 5000
In the above example, Employee is the base class and Programmer is the derived class.
C++ Single Level Inheritance Example: Inheriting Methods
Let's see another example of inheritance in C++ which inherits methods only.
- #include <iostream>
- Using namespace std;
- Class Animal {
- Public:
- Void eat() {
- Cout<<"Eating..."<<endl;
- }
- };
- Class Dog: public Animal
- {
- Public:
- Void bark(){
- Cout<<"Barking...";
- }
- };
- Int main(void) {
- Dog d1;
- d1.eat();
- d1.bark();
- Return 0;
- }
Output:
Eating...
Barking...
Let's see a simple example.
- #include <iostream>
- Using namespace std;
- Class A
- {
- Int a = 4;
- Int b = 5;
- Public:
- Int mul()
- {
- Int c = a*b;
- Return c;
- }
- };
- Class B : private A
- {
- Public:
- Void display()
- {
- Int result = mul();
- Std::cout <<"Multiplication of a and b is : "<<result<< std::endl;
- }
- };
- Int main()
- {
- B b;
- b.display();
- Return 0;
- }
Output:
Multiplication of a and b is : 20
In the above example, class A is privately inherited. Therefore, the mul() function of class 'A' cannot be accessed by the object of class B. It can only be accessed by the member function of class B.
How to make a Private Member Inheritable
The private member is not inheritable. If we modify the visibility mode by making it public, but this takes away the advantage of data hiding.
C++ introduces a third visibility modifier, i.e., protected. The member which is declared as protected will be accessible to all the member functions within the class as well as the class immediately derived from it.
Visibility modes can be classified into three categories:
- Public: When the member is declared as public, it is accessible to all the functions of the program.
- Private: When the member is declared as private, it is accessible within the class only.
- Protected: When the member is declared as protected, it is accessible within its own class as well as the class immediately derived from it.
Visibility of Inherited Members
Base class visibility | Derived class visibility | ||
Public | Private | Protected | |
Private | Not Inherited | Not Inherited | Not Inherited |
Protected | Protected | Private | Protected |
Public | Public | Private | Protected |
C++ Multilevel Inheritance
Multilevel inheritance is a process of deriving a class from another derived class.
C++ Multi Level Inheritance Example
When one class inherits another class which is further inherited by another class, it is known as multi level inheritance in C++. Inheritance is transitive so the last derived class acquires all the members of all its base classes.
Let's see the example of multi level inheritance in C++.
- #include <iostream>
- Using namespace std;
- Class Animal {
- Public:
- Void eat() {
- Cout<<"Eating..."<<endl;
- }
- };
- Class Dog: public Animal
- {
- Public:
- Void bark(){
- Cout<<"Barking..."<<endl;
- }
- };
- Class BabyDog: public Dog
- {
- Public:
- Void weep() {
- Cout<<"Weeping...";
- }
- };
- Int main(void) {
- BabyDog d1;
- d1.eat();
- d1.bark();
- d1.weep();
- Return 0;
- }
Output:
Eating...
Barking...
Weeping...
C++ Multiple Inheritance
Multiple inheritance is the process of deriving a new class that inherits the attributes from two or more classes.
Syntax of the Derived class:
- Class D : visibility B-1, visibility B-2, ?
- {
- // Body of the class;
- }
Let's see a simple example of multiple inheritance.
- #include <iostream>
- Using namespace std;
- Class A
- {
- Protected:
- Int a;
- Public:
- Void get_a(int n)
- {
- a = n;
- }
- };
- Class B
- {
- Protected:
- Int b;
- Public:
- Void get_b(int n)
- {
- b = n;
- }
- };
- Class C : public A,public B
- {
- Public:
- Void display()
- {
- Std::cout << "The value of a is : " <<a<< std::endl;
- Std::cout << "The value of b is : " <<b<< std::endl;
- Cout<<"Addition of a and b is : "<<a+b;
- }
- };
- Int main()
- {
- C c;
- c.get_a(10);
- c.get_b(20);
- c.display();
- Return 0;
- }
Output:
The value of a is : 10
The value of b is : 20
Addition of a and b is : 30
In the above example, class 'C' inherits two base classes 'A' and 'B' in a public mode.
Ambiquity Resolution in Inheritance
Ambiguity can be occurred in using the multiple inheritance when a function with the same name occurs in more than one base class.
Let's understand this through an example:
- #include <iostream>
- Using namespace std;
- Class A
- {
- Public:
- Void display()
- {
- Std::cout << "Class A" << std::endl;
- }
- };
- Class B
- {
- Public:
- Void display()
- {
- Std::cout << "Class B" << std::endl;
- }
- };
- Class C : public A, public B
- {
- Void view()
- {
- Display();
- }
- };
- Int main()
- {
- C c;
- c.display();
- Return 0;
- }
Output:
Error: reference to 'display' is ambiguous
Display();
- The above issue can be resolved by using the class resolution operator with the function. In the above example, the derived class code can be rewritten as:
- Class C : public A, public B
- {
- Void view()
- {
- A :: display(); // Calling the display() function of class A.
- B :: display(); // Calling the display() function of class B.
- }
- };
An ambiguity can also occur in single inheritance.
Consider the following situation:
- Class A
- {
- Public:
- Void display()
- {
- Cout<<?Class A?;
- }
- } ;
- Class B
- {
- Public:
- Void display()
- {
- Cout<<?Class B?;
- }
- } ;
In the above case, the function of the derived class overrides the method of the base class. Therefore, call to the display() function will simply call the function defined in the derived class. If we want to invoke the base class function, we can use the class resolution operator.
- Int main()
- {
- B b;
- b.display(); // Calling the display() function of B class.
- b.B :: display(); // Calling the display() function defined in B class.
- }
C++ Hybrid Inheritance
Hybrid inheritance is a combination of more than one type of inheritance.
Let's see a simple example:
- #include <iostream>
- Using namespace std;
- Class A
- {
- Protected:
- Int a;
- Public:
- Void get_a()
- {
- Std::cout << "Enter the value of 'a' : " << std::endl;
- Cin>>a;
- }
- };
- Class B : public A
- {
- Protected:
- Int b;
- Public:
- Void get_b()
- {
- Std::cout << "Enter the value of 'b' : " << std::endl;
- Cin>>b;
- }
- };
- Class C
- {
- Protected:
- Int c;
- Public:
- Void get_c()
- {
- Std::cout << "Enter the value of c is : " << std::endl;
- Cin>>c;
- }
- };
- Class D : public B, public C
- {
- Protected:
- Int d;
- Public:
- Void mul()
- {
- Get_a();
- Get_b();
- Get_c();
- Std::cout << "Multiplication of a,b,c is : " <<a*b*c<< std::endl;
- }
- };
- Int main()
- {
- D d;
- d.mul();
- Return 0;
- }
Output:
Enter the value of 'a' :
10
Enter the value of 'b' :
20
Enter the value of c is :
30
Multiplication of a,b,c is : 6000
C++ Hierarchical Inheritance
Hierarchical inheritance is defined as the process of deriving more than one class from a base class.
Syntax of Hierarchical inheritance:
- Class A
- {
- // body of the class A.
- }
- Class B : public A
- {
- // body of class B.
- }
- Class C : public A
- {
- // body of class C.
- }
- Class D : public A
- {
- // body of class D.
- }
Let's see a simple example:
- #include <iostream>
- Using namespace std;
- Class Shape // Declaration of base class.
- {
- Public:
- Int a;
- Int b;
- Void get_data(int n,int m)
- {
- a= n;
- b = m;
- }
- };
- Class Rectangle : public Shape // inheriting Shape class
- {
- Public:
- Int rect_area()
- {
- Int result = a*b;
- Return result;
- }
- };
- Class Triangle : public Shape // inheriting Shape class
- {
- Public:
- Int triangle_area()
- {
- Float result = 0.5*a*b;
- Return result;
- }
- };
- Int main()
- {
- Rectangle r;
- Triangle t;
- Int length,breadth,base,height;
- Std::cout << "Enter the length and breadth of a rectangle: " << std::endl;
- Cin>>length>>breadth;
- r.get_data(length,breadth);
- Int m = r.rect_area();
- Std::cout << "Area of the rectangle is : " <<m<< std::endl;
- Std::cout << "Enter the base and height of the triangle: " << std::endl;
- Cin>>base>>height;
- t.get_data(base,height);
- Float n = t.triangle_area();
- Std::cout <<"Area of the triangle is : " << n<<std::endl;
- Return 0;
- }
Output:
Enter the length and breadth of a rectangle:
23
20
Area of the rectangle is : 460
Enter the base and height of the triangle:
2
5
Area of the triangle is : 5
Polymorphism
The term "Polymorphism" is the combination of "poly" + "morphs" which means many forms. It is a greek word. In object-oriented programming, we use 3 main concepts: inheritance, encapsulation, and polymorphism.
Real Life Example Of Polymorphism
Let's consider a real-life example of polymorphism. A lady behaves like a teacher in a classroom, mother or daughter in a home and customer in a market. Here, a single person is behaving differently according to the situations.
There are two types of polymorphism in C++:
- Compile time polymorphism: The overloaded functions are invoked by matching the type and number of arguments. This information is available at the compile time and, therefore, compiler selects the appropriate function at the compile time. It is achieved by function overloading and operator overloading which is also known as static binding or early binding. Now, let's consider the case where function name and prototype is same.
- Class A // base class declaration.
- {
- Int a;
- Public:
- Void display()
- {
- Cout<< "Class A ";
- }
- };
- Class B : public A // derived class declaration.
- {
- Int b;
- Public:
- Void display()
- {
- Cout<<"Class B";
- }
- };
In the above case, the prototype of display() function is the same in both the base and derived class. Therefore, the static binding cannot be applied. It would be great if the appropriate function is selected at the run time. This is known as run time polymorphism.
- Run time polymorphism: Run time polymorphism is achieved when the object's method is invoked at the run time instead of compile time. It is achieved by method overriding which is also known as dynamic binding or late binding.
Differences b/w compile time and run time polymorphism.
Compile time polymorphism | Run time polymorphism |
The function to be invoked is known at the compile time. | The function to be invoked is known at the run time. |
It is also known as overloading, early binding and static binding. | It is also known as overriding, Dynamic binding and late binding. |
Overloading is a compile time polymorphism where more than one method is having the same name but with the different number of parameters or the type of the parameters. | Overriding is a run time polymorphism where more than one method is having the same name, number of parameters and the type of the parameters. |
It is achieved by function overloading and operator overloading. | It is achieved by virtual functions and pointers. |
It provides fast execution as it is known at the compile time. | It provides slow execution as it is known at the run time. |
It is less flexible as mainly all the things execute at the compile time. | It is more flexible as all the things execute at the run time. |
C++ Runtime Polymorphism Example
Let's see a simple example of run time polymorphism in C++.
// an example without the virtual keyword.
- #include <iostream>
- Using namespace std;
- Class Animal {
- Public:
- Void eat(){
- Cout<<"Eating...";
- }
- };
- Class Dog: public Animal
- {
- Public:
- Void eat()
- { cout<<"Eating bread...";
- }
- };
- Int main(void) {
- Dog d = Dog();
- d.eat();
- Return 0;
- }
Output:
Eating bread...
C++ Run time Polymorphism Example: By using two derived class
Let's see another example of run time polymorphism in C++ where we are having two derived classes.
// an example with virtual keyword.
- #include <iostream>
- Using namespace std;
- Class Shape { // base class
- Public:
- Virtual void draw(){ // virtual function
- Cout<<"drawing..."<<endl;
- }
- };
- Class Rectangle: public Shape // inheriting Shape class.
- {
- Public:
- Void draw()
- {
- Cout<<"drawing rectangle..."<<endl;
- }
- };
- Class Circle: public Shape // inheriting Shape class.
- {
- Public:
- Void draw()
- {
- Cout<<"drawing circle..."<<endl;
- }
- };
- Int main(void) {
- Shape *s; // base class pointer.
- Shape sh; // base class object.
- Rectangle rec;
- Circle cir;
- s=&sh;
- s->draw();
- s=&rec;
- s->draw();
- s=?
- s->draw();
- }
Output:
Drawing...
Drawing rectangle...
Drawing circle...
Runtime Polymorphism with Data Members
Runtime Polymorphism can be achieved by data members in C++. Let's see an example where we are accessing the field by reference variable which refers to the instance of derived class.
- #include <iostream>
- Using namespace std;
- Class Animal { // base class declaration.
- Public:
- String color = "Black";
- };
- Class Dog: public Animal // inheriting Animal class.
- {
- Public:
- String color = "Grey";
- };
- Int main(void) {
- Animal d= Dog();
- Cout<<d.color;
- }
Output:
Black
KEY TAKEAWAY
Objects
Objects are the basic run time entities in an object-oriented system. They may represent a person, a place, a bank account, a table of data or any item that the program has to handle. They may also represent user-defined data such as vectors, time and lists.
Classes
We just mentioned that objects contain data, and code to manipulate that data. The entire set of data and code of an object can be made a user-defined data type with the help of class. In fact, objects are variables of the type class. Once a class has been defined, we can create any number of objects belonging to that class. Each object is associated with the data of type class with which they are created. A class is thus a collection of objects similar types.
Data Members
"Data Member" and "Member Functions" are the new names/terms for the members of a class, which are introduced in C++ programming language.
The variables which are declared in any class by using any fundamental data types (like int, char, float etc) or derived data type (like class, structure, pointer etc.) are known as Data Members. And the functions which are declared either in private section of public section are known as Member functions.
Methods
A function is a group of statements that together perform a task. Every C++ program has at least one function, which is main(), and all the most trivial programs can define additional functions.
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is such that each function performs a specific task.
A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
Data Encapsulation
Encapsulation is an Object Oriented Programming concept that binds together the data and functions that manipulate the data, and that keeps both safe from outside interference and misuse. Data encapsulation led to the important OOP concept of data hiding.
Data encapsulation is a mechanism of bundling the data, and the functions that use them and data abstraction is a mechanism of exposing only the interfaces and hiding the implementation details from the user.
Data Abstraction
Data abstraction refers to providing only essential information to the outside world and hiding their background details, i.e., to represent the needed information in program without presenting the details.
Data abstraction is a programming (and design) technique that relies on the separation of interface and implementation.
Information Hiding
Information hiding is a principle of OOP, where a stable interface is open to the rest of the program while its implementation details are hidden. This is usually achieved in OO languages (such as C++ and Java) by controlling access over the methods and fields of a class.
The problem is that C has only structs and their fields are always public, so the rest of the program always has access to the struct fields. This introduces the danger of higher coupling between modules, by directly manipulating the fields of a foreign data structure.
Inheritance
In C++, inheritance is a process in which one object acquires all the properties and behaviors of its parent object automatically. In such way, you can reuse, extend or modify the attributes and behaviors which are defined in other class.
In C++, the class which inherits the members of another class is called derived class and the class whose members are inherited is called base class. The derived class is the specialized class for the base class.
Polymorphism
The term "Polymorphism" is the combination of "poly" + "morphs" which means many forms. It is a greek word. In object-oriented programming, we use 3 main concepts: inheritance, encapsulation, and polymorphism.
- Inline functions are functions which are replaced by corresponding function code for a function call.
- Usually function call takes control to corresponding function definition.
- This involves executing series of instructions, pushing elements in stack, saving register and coming back to function call.
- This process consumes execution time.
- So if function definition is very small(one or two statements)then instead of passing control to function definition function call is replaced by its corresponding code.Such functions are called as inline functions.
- Inline functions are defined using keyword inline as follows :
Inline return-type function-name(argument list)
{
Function body
}
Example
Inline int add(int x,int y, int z)
{
Return(x*y*z);
}
- Function call
Add(10,20,25);
Will be expanded by its function definition.
- Though we define function as inline compiler may ignore the request in following cases
- Function definition is large.
- Function is recursive
- Function return values
Program
Write a C++ program to illustrate inline functions.
Solution :
# include<iostream>
Using namespace std ;
Inline void data(int x) // Step 1 Defines function data as inline
{
Return (x%2==0)?cout<<“Even\n”:cout<<“Odd”; // Step 2
}
Void main()
{
Data(10); // Step 3 Calling inline function
Data(5); // Step 4
}
Explanation
Step 1 : Function data is declared as inline with one argument.
It finds if a number is even or odd.
Inline void data(int x) | //Defines function data as inline |
Step 2 : Conditional operator is used to check if number is even or odd.
Return (x%2==0)?cout<<“Even\n”:cout<<“Odd”; |
Step 3 : Pass parameter 10 to data function. Here data function is expanded to its corresponding code instead of passing control to function definition. It gives output as even number.
Data(10); |
Step 4 : Pass parameter 5 to data function. It gives output as odd number.
Data(5); |
Output
Even
Odd
C++ Programming- C++ programming Basics
When we consider a C++ program, it can be defined as a collection of objects that communicate via invoking each other's methods. Let us now briefly look into what a class, object, methods, and instant variables mean.
- Object− Objects have states and behaviors. Example: A dog has states - color, name, breed as well as behaviors - wagging, barking, eating. An object is an instance of a class.
- Class− A class can be defined as a template/blueprint that describes the behaviors/states that object of its type support.
- Methods− A method is basically a behavior. A class can contain many methods. It is in methods where the logics are written, data is manipulated and all the actions are executed.
- Instance Variables− Each object has its unique set of instance variables. An object's state is created by the values assigned to these instance variables.
C++ Program Structure
Let us look at a simple code that would print the words Hello World.
#include<iostream>
Usingnamespace std;
// main() is where program execution begins.
Intmain(){
Cout<<"Hello World";// prints Hello World
Return0;
}
Let us look at the various parts of the above program −
- The C++ language defines several headers, which contain information that is either necessary or useful to your program. For this program, the header <iostream> is needed.
- The line using namespace std; tells the compiler to use the std namespace. Namespaces are a relatively recent addition to C++.
- The next line '// main() is where program execution begins.' is a single-line comment available in C++. Single-line comments begin with // and stop at the end of the line.
- The line int main() is the main function where program execution begins.
- The next line cout<< "Hello World"; causes the message "Hello World" to be displayed on the screen.
- The next line return 0; terminates main( )function and causes it to return the value 0 to the calling process.
Compile and Execute C++ Program
Let's look at how to save the file, compile and run the program. Please follow the steps given below −
- Open a text editor and add the code as above.
- Save the file as: hello.cpp
- Open a command prompt and go to the directory where you saved the file.
- Type 'g++ hello.cpp' and press enter to compile your code. If there are no errors in your code the command prompt will take you to the next line and would generate a.out executable file.
- Now, type 'a.out' to run your program.
- You will be able to see ' Hello World ' printed on the window.
$ g++ hello.cpp
$ ./a.out
Hello World
Make sure that g++ is in your path and that you are running it in the directory containing file hello.cpp.
You can compile C/C++ programs using makefile.
Semicolons and Blocks in C++
In C++, the semicolon is a statement terminator. That is, each individual statement must be ended with a semicolon. It indicates the end of one logical entity.
For example, following are three different statements −
x = y;
y = y + 1;
Add(x, y);
A block is a set of logically connected statements that are surrounded by opening and closing braces. For example −
{
Cout<< "Hello World"; // prints Hello World
Return 0;
}
C++ does not recognize the end of the line as a terminator. For this reason, it does not matter where you put a statement in a line. For example −
x = y;
y = y + 1;
Add(x, y);
Is the same as
x = y; y = y + 1; add(x, y);
C++ Identifiers
A C++ identifier is a name used to identify a variable, function, class, module, or any other user-defined item. An identifier starts with a letter A to Z or a to z or an underscore (_) followed by zero or more letters, underscores, and digits (0 to 9).
C++ does not allow punctuation characters such as @, $, and % within identifiers. C++ is a case-sensitive programming language. Thus, Manpower and manpower are two different identifiers in C++.
Here are some examples of acceptable identifiers −
Mohdzaraabcmove_name a_123
Myname50 _temp j a23b9 retVal
C++ Keywords
The following list shows the reserved words in C++. These reserved words may not be used as constant or variable or any other identifier names.
Asm | Else | New | This |
Auto | Enum | Operator | Throw |
Bool | Explicit | Private | True |
Break | Export | Protected | Try |
Case | Extern | Public | Typedef |
Catch | False | Register | Typeid |
Char | Float | Reinterpret_cast | Typename |
Class | For | Return | Union |
Const | Friend | Short | Unsigned |
Const_cast | Goto | Signed | Using |
Continue | If | Sizeof | Virtual |
Default | Inline | Static | Void |
Delete | Int | Static_cast | Volatile |
Do | Long | Struct | Wchar_t |
Double | Mutable | Switch | While |
Dynamic_cast | Namespace | Template |
|
Trigraphs
A few characters have an alternative representation, called a trigraph sequence. A trigraph is a three-character sequence that represents a single character and the sequence always starts with two question marks.
Trigraphs are expanded anywhere they appear, including within string literals and character literals, in comments, and in preprocessor directives.
Following are most frequently used trigraph sequences −
Trigraph | Replacement |
??= | # |
??/ | \ |
??' | ^ |
??( | [ |
??) | ] |
??! | | |
??< | { |
??> | } |
??- | ~ |
All the compilers do not support trigraphs and they are not advised to be used because of their confusing nature.
Whitespace in C++
A line containing only whitespace, possibly with a comment, is known as a blank line, and C++ compiler totally ignores it.
Whitespace is the term used in C++ to describe blanks, tabs, newline characters and comments. Whitespace separates one part of a statement from another and enables the compiler to identify where one element in a statement, such as int, ends and the next element begins.
Statement 1
Int age;
In the above statement there must be at least one whitespace character (usually a space) between int and age for the compiler to be able to distinguish them.
Statement 2
Fruit = apples + oranges; // Get the total fruit
In the above statement 2, no whitespace characters are necessary between fruit and =, or between = and apples, although you are free to include some if you wish for readability purpose.
KEY TAKEAWAY
- Inline functions are functions which are replaced by corresponding function code for a function call.
- Usually function call takes control to corresponding function definition.
- This involves executing series of instructions, pushing elements in stack, saving register and coming back to function call.
If we create two or more members having the same name but different in number or type of parameter, it is known as C++ overloading. In C++, we can overload:
- Methods,
- Constructors, and
- Indexed properties
It is because these members have parameters only.
Types of overloading in C++ are:
- Function overloading
- Operator overloading
C++ Function Overloading
Function Overloading is defined as the process of having two or more function with the same name, but different in parameters is known as function overloading in C++. In function overloading, the function is redefined by using either different types of arguments or a different number of arguments. It is only through these differences compiler can differentiate between the functions.
The advantage of Function overloading is that it increases the readability of the program because you don't need to use different names for the same action.
C++ Function Overloading Example
Let's see the simple example of function overloading where we are changing number of arguments of add() method.
// program of function overloading when number of arguments vary.
- #include <iostream>
- Using namespace std;
- Class Cal {
- Public:
- Static int add(int a,int b){
- Return a + b;
- }
- Static int add(int a, int b, int c)
- {
- Return a + b + c;
- }
- };
- Int main(void) {
- Cal C; // class object declaration.
- Cout<<C.add(10, 20)<<endl;
- Cout<<C.add(12, 20, 23);
- Return 0;
- }
Output:
30
55
Let's see the simple example when the type of the arguments vary.
// Program of function overloading with different types of arguments.
- #include<iostream>
- Using namespace std;
- Int mul(int,int);
- Float mul(float,int);
- Int mul(int a,int b)
- {
- Return a*b;
- }
- Float mul(double x, int y)
- {
- Return x*y;
- }
- Int main()
- {
- Int r1 = mul(6,7);
- Float r2 = mul(0.2,3);
- Std::cout << "r1 is : " <<r1<< std::endl;
- Std::cout <<"r2 is : " <<r2<< std::endl;
- Return 0;
- }
Output:
r1 is : 42
r2 is : 0.6
Function Overloading and Ambiguity
When the compiler is unable to decide which function is to be invoked among the overloaded function, this situation is known as function overloading.
When the compiler shows the ambiguity error, the compiler does not run the program.
Causes of Function Overloading:
- Type Conversion.
- Function with default arguments.
- Function with pass by reference.
- Type Conversion:
Let's see a simple example.
- #include<iostream>
- Using namespace std;
- Void fun(int);
- Void fun(float);
- Void fun(int i)
- {
- Std::cout << "Value of i is : " <<i<< std::endl;
- }
- Void fun(float j)
- {
- Std::cout << "Value of j is : " <<j<< std::endl;
- }
- Int main()
- {
- Fun(12);
- Fun(1.2);
- Return 0;
- }
The above example shows an error "call of overloaded 'fun(double)' is ambiguous". The fun(10) will call the first function. The fun(1.2) calls the second function according to our prediction. But, this does not refer to any function as in C++, all the floating point constants are treated as double not as a float. If we replace float to double, the program works. Therefore, this is a type conversion from float to double.
- Function with Default Arguments
Let's see a simple example.
- #include<iostream>
- Using namespace std;
- Void fun(int);
- Void fun(int,int);
- Void fun(int i)
- {
- Std::cout << "Value of i is : " <<i<< std::endl;
- }
- Void fun(int a,int b=9)
- {
- Std::cout << "Value of a is : " <<a<< std::endl;
- Std::cout << "Value of b is : " <<b<< std::endl;
- }
- Int main()
- {
- Fun(12);
- Return 0;
- }
The above example shows an error "call of overloaded 'fun(int)' is ambiguous". The fun(int a, int b=9) can be called in two ways: first is by calling the function with one argument, i.e., fun(12) and another way is calling the function with two arguments, i.e., fun(4,5). The fun(int i) function is invoked with one argument. Therefore, the compiler could not be able to select among fun(int i) and fun(int a,int b=9).
- Function with pass by reference
Let's see a simple example.
- #include <iostream>
- Using namespace std;
- Void fun(int);
- Void fun(int &);
- Int main()
- {
- Int a=10;
- Fun(a); // error, which f()?
- Return 0;
- }
- Void fun(int x)
- {
- Std::cout << "Value of x is : " <<x<< std::endl;
- }
- Void fun(int &b)
- {
- Std::cout << "Value of b is : " <<b<< std::endl;
- }
The above example shows an error "call of overloaded 'fun(int&)' is ambiguous". The first function takes one integer argument and the second function takes a reference parameter as an argument. In this case, the compiler does not know which function is needed by the user as there is no syntactical difference between the fun(int) and fun(int &).
C++ Operators Overloading
Operator overloading is a compile-time polymorphism in which the operator is overloaded to provide the special meaning to the user-defined data type. Operator overloading is used to overload or redefines most of the operators available in C++. It is used to perform the operation on the user-defined data type. For example, C++ provides the ability to add the variables of the user-defined data type that is applied to the built-in data types.
The advantage of Operators overloading is to perform different operations on the same operand.
Operator that cannot be overloaded are as follows:
- Scope operator (::)
- Sizeof
- Member selector(.)
- Member pointer selector(*)
- Ternary operator(?:)
Syntax of Operator Overloading
- Return_type class_name : : operator op(argument_list)
- {
- // body of the function.
- }
Where the return type is the type of value returned by the function.
Class_name is the name of the class.
Operator op is an operator function where op is the operator being overloaded, and the operator is the keyword.
Rules for Operator Overloading
- Existing operators can only be overloaded, but the new operators cannot be overloaded.
- The overloaded operator contains atleast one operand of the user-defined data type.
- We cannot use friend function to overload certain operators. However, the member function can be used to overload those operators.
- When unary operators are overloaded through a member function take no explicit arguments, but, if they are overloaded by a friend function, takes one argument.
- When binary operators are overloaded through a member function takes one explicit argument, and if they are overloaded through a friend function takes two explicit arguments.
C++ Operators Overloading Example
Let's see the simple example of operator overloading in C++. In this example, void operator ++ () operator function is defined (inside Test class).
// program to overload the unary operator ++.
- #include <iostream>
- Using namespace std;
- Class Test
- {
- Private:
- Int num;
- Public:
- Test(): num(8){}
- Void operator ++() {
- Num = num+2;
- }
- Void Print() {
- Cout<<"The Count is: "<<num;
- }
- };
- Int main()
- {
- Test tt;
- ++tt; // calling of a function "void operator ++()"
- Tt.Print();
- Return 0;
- }
Output:
The Count is: 10
Let's see a simple example of overloading the binary operators.
// program to overload the binary operators.
- #include <iostream>
- Using namespace std;
- Class A
- {
- Int x;
- Public:
- A(){}
- A(int i)
- {
- x=i;
- }
- Void operator+(A);
- Void display();
- };
- Void A :: operator+(A a)
- {
- Int m = x+a.x;
- Cout<<"The result of the addition of two objects is : "<<m;
- }
- Int main()
- {
- A a1(5);
- A a2(4);
- a1+a2;
- Return 0;
- }
Output:
The result of the addition of two objects is : 9
KEY TAKEAWAY
If we create two or more members having the same name but different in number or type of parameter, it is known as C++ overloading. In C++, we can overload:
- Methods,
- Constructors, and
- Indexed properties
It is because these members have parameters only.
There are two ways to pass value or data to function in C language: call by value and call by reference. Original value is not modified in call by value but it is modified in call by reference.
Let's understand call by value and call by reference in C++ language one by one.
Call by value in C++
In call by value, original value is not modified.
In call by value, value being passed to the function is locally stored by the function parameter in stack memory location. If you change the value of function parameter, it is changed for the current function only. It will not change the value of variable inside the caller method such as main().
Let's try to understand the concept of call by value in C++ language by the example given below:
- #include <iostream>
- Using namespace std;
- Void change(int data);
- Int main()
- {
- Int data = 3;
- Change(data);
- Cout << "Value of the data is: " << data<< endl;
- Return 0;
- }
- Void change(int data)
- {
- Data = 5;
- }
Output:
Value of the data is: 3
Call by reference in C++
In call by reference, original value is modified because we pass reference (address).
Here, address of the value is passed in the function, so actual and formal arguments share the same address space. Hence, value changed inside the function, is reflected inside as well as outside the function.
Note: To understand the call by reference, you must have the basic knowledge of pointers.
Let's try to understand the concept of call by reference in C++ language by the example given below:
- #include<iostream>
- Using namespace std;
- Void swap(int *x, int *y)
- {
- Int swap;
- Swap=*x;
- *x=*y;
- *y=swap;
- }
- Int main()
- {
- Int x=500, y=100;
- Swap(&x, &y); // passing value to function
- Cout<<"Value of x is: "<<x<<endl;
- Cout<<"Value of y is: "<<y<<endl;
- Return 0;
- }
Output:
Value of x is: 100
Value of y is: 500
Difference between call by value and call by reference in C++
No. | Call by value | Call by reference |
1 | A copy of value is passed to the function | An address of value is passed to the function |
2 | Changes made inside the function is not reflected on other functions | Changes made inside the function is reflected outside the function also |
3 | Actual and formal arguments will be created in different memory location | Actual and formal arguments will be created in same memory location |
KEY TAKEAWAY
There are two ways to pass value or data to function in C language: call by value and call by reference. Original value is not modified in call by value but it is modified in call by reference.
A C++ program can be made easier to read and maintain by using references rather than pointers. A C++ function can return a reference in a similar way as it returns a pointer.
When a function returns a reference, it returns an implicit pointer to its return value. This way, a function can be used on the left side of an assignment statement. For example, consider this simple program −
#include <iostream>
#include <ctime>
Using namespace std;
Double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
Double& setValues( int i ) {
Return vals[i]; // return a reference to the ith element
}
// main function to call above defined function.
Int main () {
Cout << "Value before change" << endl;
For ( int i = 0; i < 5; i++ ) {
Cout << "vals[" << i << "] = ";
Cout << vals[i] << endl;
}
SetValues(1) = 20.23; // change 2nd element
SetValues(3) = 70.8; // change 4th element
Cout << "Value after change" << endl;
For ( int i = 0; i < 5; i++ ) {
Cout << "vals[" << i << "] = ";
Cout << vals[i] << endl;
}
Return 0;
}
When the above code is compiled together and executed, it produces the following result −
Value before change
Vals[0] = 10.1
Vals[1] = 12.6
Vals[2] = 33.1
Vals[3] = 24.1
Vals[4] = 50
Value after change
Vals[0] = 10.1
Vals[1] = 20.23
Vals[2] = 33.1
Vals[3] = 70.8
Vals[4] = 50
When returning a reference, be careful that the object being referred to does not go out of scope. So it is not legal to return a reference to local var. But you can always return a reference on a static variable.
Int& func() {
Int q;
//! return q; // Compile time error
Static int x;
Return x; // Safe, x lives outside this scope
}
KEY TAKEAWAY
A C++ program can be made easier to read and maintain by using references rather than pointers. A C++ function can return a reference in a similar way as it returns a pointer.
When a function returns a reference, it returns an implicit pointer to its return value. This way, a function can be used on the left side of an assignment statement.
Default arguments are those which are provided to the called function in case the caller statement does provide any value for them.
Example
#include<iostream>
Using namespace std;
//function defined with default arguments
Int sum(int x, int y, int z=0, int w=0){
Return (x + y + z + w);
}
Int main(){
Cout << sum(10, 15) << endl;
Cout << sum(10, 15, 25) << endl;
Cout << sum(10, 15, 25, 30) << endl;
Return 0;
}
Output
25
50
80
KEY TAKEAWAY
Default arguments are those which are provided to the called function in case the caller statement does provide any value for them.
In C++ programming, this is a keyword that refers to the current instance of the class. There can be 3 main usage of this keyword in C++.
- It can be used to pass current object as a parameter to another method.
- It can be used to refer current class instance variable.
- It can be used to declare indexers.
C++ this Pointer Example
Let's see the example of this keyword in C++ that refers to the fields of current class.
- #include <iostream>
- Using namespace std;
- Class Employee {
- Public:
- Int id; //data member (also instance variable)
- String name; //data member(also instance variable)
- Float salary;
- Employee(int id, string name, float salary)
- {
- This->id = id;
- This->name = name;
- This->salary = salary;
- }
- Void display()
- {
- Cout<<id<<" "<<name<<" "<<salary<<endl;
- }
- };
- Int main(void) {
- Employee e1 =Employee(101, "Sonoo", 890000); //creating an object of Employee
- Employee e2=Employee(102, "Nakul", 59000); //creating an object of Employee
- e1.display();
- e2.display();
- Return 0;
- }
Output:
101 Sonoo 890000
102 Nakul 59000
KEY TAKEAWAY
In C++ programming, this is a keyword that refers to the current instance of the class. There can be 3 main usage of this keyword in C++.
- It can be used to pass current object as a parameter to another method.
- It can be used to refer current class instance variable.
- It can be used to declare indexers.
Simple Class Addition: Add Two Integers Example Program
/* Simple Class Addition: Add Two Integers Example Program In C++
Understanding Class */
// Header Files
Using namespace std;
// Addition Class Declaration
Class AdditionClass {
Private://Access - Specifier
//Member Variable Declaration
Int num1, num2, result;
Public://Access - Specifier
//Member Functions read(),sum() and print() Declaration
Void read() {
//Get Input Values For Object Variables using cin
Cout << "Enter Number 1 :";
Cin >> num1;
Cout << "Enter Number 2 :";
Cin >> num2;
}
Void sum() {
// Calculating sum value and assign in 'result'
Result = num1 + num2;
}
Void print() {
//Print the Output using cout
Cout << "Result :" << num1 << " + " << num1 << " = " << result << endl;
}
};
Int main() {
// Object Creation For Class
AdditionClass obj1, obj2;
Cout << "Simple Class Addition : Add Two Integers In C++\n";
Cout << "\nAdditionClass : obj1 Usage" << endl;
Obj1.read();
Obj1.sum();
Obj1.print();
Cout << "\nAdditionClass : obj2 Usage" << endl;
Obj2.read();
Obj2.sum();
Obj2.print();
Getch();
Return 0;
}
Sample Output
Simple Class Addition: Add Two Integers In C++
AdditionClass : obj1 Usage
Enter Number 1 :100
Enter Number 2 :200
Result :100 + 100 = 300
AdditionClass : obj2 Usage
Enter Number 1 :700
Enter Number 2 :900
Result :700 + 700 = 1600
Read and Print Student Information Class Example Program
/* Read and Print Student Information Class Example Program In C++ */
/* Class C++ Programs, Understanding Class,C++ Examples */
// Header Files
Using namespace std;
// Student Class Declaration
Class StudentClass {
Private://Access - Specifier
//Member Variable Declaration
Char name[20];
Int regNo, sub1, sub2, sub3;
Float total, avg;
Public://Access - Specifier
//Member Functions read() and print() Declaration
Void read() {
//Get Input Values For Object Variables
Cout << "Enter Name :";
Cin >> name;
Cout << "Enter Registration Number :";
Cin >> regNo;
Cout << "Enter Marks for Subject 1,2 and 3 :";
Cin >> sub1 >> sub2>> sub3;
}
Void sum() {
Total = sub1 + sub2 + sub3;
Avg = total / 3;
}
Void print() {
//Show the Output
Cout << "Name :" << name << endl;
Cout << "Registration Number :" << regNo << endl;
Cout << "Marks :" << sub1 << " , " << sub2 << " , " << sub3 << endl;
Cout << "Total :" << total << endl;
Cout << "Average :" << avg << endl;
}
};
Int main() {
// Object Creation For Class
StudentClass stu1, stu2;
Cout << "Read and Print Student Information Class Example Program In C++\n";
Cout << "\nStudentClass : Student 1" << endl;
Stu1.read();
Stu1.sum();
Stu1.print();
Cout << "\nStudentClass : Student 2" << endl;
Stu2.read();
Stu2.sum();
Stu2.print();
Getch();
Return 0;
}
Sample Output
Read and Print Student Information Class Example Program In C++
StudentClass : Student 1
Enter Name :Mask
Enter Registration Number :10001
Enter Marks for Subject 1,2 and 3 :90
80
65
Name :Mask
Registration Number :10001
Marks :90 , 80 , 65
Total :235
Average :78.3333
StudentClass : Student 2
Enter Name :Operas
Enter Registration Number :10002
Enter Marks for Subject 1,2 and 3 :95
85
70
Name :Operas
Registration Number :10002
Marks :95 , 85 , 70
Total :250
Average :83.3333
Dynamic initialization of object refers to initializing the objects at run time i.e. the initial value of an object is to be provided during run time. Dynamic initialization can be achieved using constructors and passing parameters values to the constructors. This type of initialization is required to initialize the class variables during run time.
Why we need the dynamic initialization?
Dynamic initialization of objects is needed as
- It utilizes memory efficiently.
- Various initialization formats can be provided using overloaded constructors.
- It has the flexibility of using different formats of data at run time considering the situation.
Example Code
#include <iostream>
Using namespace std;
Class simple_interest {
Float principle , time, rate ,interest;
Public:
Simple_interest (float a, float b, float c) {
Principle = a;
Time =b;
Rate = c;
}
Void display ( ) {
Interest =(principle* rate* time)/100;
Cout<<"interest ="<<interest ;
}
};
Int main() {
Float p,r,t;
Cout<<"principle amount, time and rate"<<endl;
Cout<<"2000 7.5 2"<<endl;
Simple_interest s1(2000,7.5,2);//dynamic initialization
s1.display();
Return 1;
}
Output
Enter principle amount ,rate and time
2000 7.5 2
Interest =300
A good understanding of how dynamic memory really works in C++ is essential to becoming a good C++ programmer. Memory in your C++ program is divided into two parts −
- The stack− All variables declared inside the function will take up memory from the stack.
- The heap− This is unused memory of the program and can be used to allocate the memory dynamically when program runs.
Many times, you are not aware in advance how much memory you will need to store particular information in a defined variable and the size of required memory can be determined at run time.
You can allocate memory at run time within the heap for the variable of a given type using a special operator in C++ which returns the address of the space allocated. This operator is called new operator.
If you are not in need of dynamically allocated memory anymore, you can use delete operator, which de-allocates memory that was previously allocated by new operator.
New and delete Operators
There is following generic syntax to use new operator to allocate memory dynamically for any data-type.
New data-type;
Here, data-type could be any built-in data type including an array or any user defined data types include class or structure. Let us start with built-in data types. For example we can define a pointer to type double and then request that the memory be allocated at execution time. We can do this using the new operator with the following statements −
Double* pvalue = NULL; // Pointer initialized with null
Pvalue = new double; // Request memory for the variable
The memory may not have been allocated successfully, if the free store had been used up. So it is good practice to check if new operator is returning NULL pointer and take appropriate action as below −
Double* pvalue = NULL;
If( !(pvalue = new double )) {
Cout<< "Error: out of memory." <<endl;
Exit(1);
}
The malloc() function from C, still exists in C++, but it is recommended to avoid using malloc() function. The main advantage of new over malloc() is that new doesn't just allocate memory, it constructs objects which is prime purpose of C++.
At any point, when you feel a variable that has been dynamically allocated is not anymore required, you can free up the memory that it occupies in the free store with the ‘delete’ operator as follows −
Delete pvalue; // Release memory pointed to by pvalue
Let us put above concepts and form the following example to show how ‘new’ and ‘delete’ work −
#include<iostream>
Usingnamespace std;
Int main (){
Double*pvalue= NULL;// Pointer initialized with null
Pvalue=newdouble;// Request memory for the variable
*pvalue=29494.99;// Store value at allocated address
Cout<<"Value of pvalue : "<<*pvalue<<endl;
Deletepvalue;// free up the memory.
Return0;
}
If we compile and run above code, this would produce the following result −
Value of pvalue : 29495
Dynamic Memory Allocation for Arrays
Consider you want to allocate memory for an array of characters, i.e., string of 20 characters. Using the same syntax what we have used above we can allocate memory dynamically as shown below.
Char* pvalue = NULL; // Pointer initialized with null
Pvalue = new char[20]; // Request memory for the variable
To remove the array that we have just created the statement would look like this −
Delete [] pvalue; // Delete array pointed to by pvalue
Following the similar generic syntax of new operator, you can allocate for a multi-dimensional array as follows −
Double** pvalue = NULL; // Pointer initialized with null
Pvalue = new double [3][4]; // Allocate memory for a 3x4 array
However, the syntax to release the memory for multi-dimensional array will still remain same as above −
Delete [] pvalue; // Delete array pointed to by pvalue
Dynamic Memory Allocation for Objects
Objects are no different from simple data types. For example, consider the following code where we are going to use an array of objects to clarify the concept −
#include<iostream>
Usingnamespace std;
ClassBox{
Public:
Box(){
Cout<<"Constructor called!"<<endl;
}
~Box(){
Cout<<"Destructor called!"<<endl;
}
};
Intmain(){
Box*myBoxArray=newBox[4];
Delete[]myBoxArray;// Delete array
Return0;
}
If you were to allocate an array of four Box objects, the Simple constructor would be called four times and similarly while deleting these objects, destructor will also be called same number of times.
If we compile and run above code, this would produce the following result −
Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
KEY TAKEAWAY
Dynamic initialization of object refers to initializing the objects at run time i.e. the initial value of an object is to be provided during run time. Dynamic initialization can be achieved using constructors and passing parameters values to the constructors. This type of initialization is required to initialize the class variables during run time.
Operator precedence determines the grouping of terms in an expression. The associativity of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses. This affects how an expression is evaluated. Certain operators have higher precedence than others; for example, the multiplication operator has higher precedence than the addition operator:
For example x = 7 + 3 * 2; here, x is assigned 13, not 20 because operator * has higher precedence than +, so it first gets multiplied with 3*2 and then adds into 7.
Here, operators with the highest precedence appear at the top of the table, those with the lowest appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Category | Operator | Associativity |
Postfix | () [] -> . ++ - - | Left to right |
Unary | + - ! ~ ++ - - (type)* & sizeof | Right to left |
Multiplicative | * / % | Left to right |
Additive | + - | Left to right |
Shift | << >> | Left to right |
Relational | < <= > >= | Left to right |
Equality | == != | Left to right |
Bitwise AND | & | Left to right |
Bitwise XOR | ^ | Left to right |
Bitwise OR | | | Left to right |
Logical AND | && | Left to right |
Logical OR | || | Left to right |
Conditional | ?: | Right to left |
Assignment | = += -= *= /= %=>>= <<= &= ^= |= | Right to left |
Comma | , | Left to right |
KEY TAKEAWAY
Operator precedence determines the grouping of terms in an expression. The associativity of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses.
A cast is a special operator that forces one data type to be converted into another. As an operator, a cast is unary and has the same precedence as any other unary operator.
The most general cast supported by most of the C++ compilers is as follows −
(type) expression
Where type is the desired data type. There are other casting operators supported by C++, they are listed below −
- Const_cast<type> (expr) − The const_cast operator is used to explicitly override const and/or volatile in a cast. The target type must be the same as the source type except for the alteration of its const or volatile attributes. This type of casting manipulates the const attribute of the passed object, either to be set or removed.
- Dynamic_cast<type> (expr) − The dynamic_cast performs a runtime cast that verifies the validity of the cast. If the cast cannot be made, the cast fails and the expression evaluates to null. A dynamic_cast performs casts on polymorphic types and can cast a A* pointer into a B* pointer only if the object being pointed to actually is a B object.
- Reinterpret_cast<type> (expr) − The reinterpret_cast operator changes a pointer to any other type of pointer. It also allows casting from pointer to an integer type and vice versa.
- Static_cast<type> (expr) − The static_cast operator performs a nonpolymorphic cast. For example, it can be used to cast a base class pointer into a derived class pointer.
All of the above-mentioned casting operators will be used while working with classes and objects. For now, try the following example to understand a simple cast operators available in C++. Copy and paste the following C++ program in test.cpp file and compile and run this program.
#include <iostream>
Using namespace std;
Main() {
Double a = 21.09399;
Float b = 10.20;
Int c ;
c = (int) a;
Cout << "Line 1 - Value of (int)a is :" << c << endl ;
c = (int) b;
Cout << "Line 2 - Value of (int)b is :" << c << endl ;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Line 1 - Value of (int)a is :21
Line 2 - Value of (int)b is :10
KEY TAKEAWAY
A cast is a special operator that forces one data type to be converted into another. As an operator, a cast is unary and has the same precedence as any other unary operator.
The most general cast supported by most of the C++ compilers is as follows −
(type) expression
The :: (scope resolution) operator is used to get hidden names due to variable scopes so that you can still use them. The scope resolution operator can be used as both unary and binary. You can use the unary scope operator if a namespace scope or global scope name is hidden by a particular declaration of an equivalent name during a block or class. For example, if you have a global variable of name my_var and a local variable of name my_var, to access global my_var, you'll need to use the scope resolution operator.
Example
#include <iostream>
Using namespace std;
Int my_var = 0;
Int main(void) {
Int my_var = 0;
::my_var = 1; // set global my_var to 1
My_var = 2; // set local my_var to 2
Cout << ::my_var << ", " << my_var;
Return 0;
}
Output
This will give the output −
1, 2
The declaration of my_var declared in the main function hides the integer named my_var declared in global namespace scope. The statement ::my_var = 1 accesses the variable named my_var declared in global namespace scope.
You can also use the scope resolution operator to use class names or class member names. If a class member name is hidden, you can use it by prefixing it with its class name and the class scope operator. For example,
Example
#include <iostream>
Using namespace std;
Class X {
Public:
Static int count;
};
Int X::count = 10; // define static data member
Int main () {
Int X = 0; // hides class type X
Cout << X::count << endl; // use static member of class X
}
Output
This will give the output −
10
KEY TAKEAWAY
The :: (scope resolution) operator is used to get hidden names due to variable scopes so that you can still use them. The scope resolution operator can be used as both unary and binary.
C++ provides a data structure, the array, which stores a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type.
Instead of declaring individual variables, such as number0, number1, ..., and number99, you declare one array variable such as numbers and use numbers[0], numbers[1], and ..., numbers[99] to represent individual variables. A specific element in an array is accessed by an index.
All arrays consist of contiguous memory locations. The lowest address corresponds to the first element and the highest address to the last element.
Declaring Arrays
To declare an array in C++, the programmer specifies the type of the elements and the number of elements required by an array as follows −
Type arrayName [ arraySize ];
This is called a single-dimension array. The arraySize must be an integer constant greater than zero and type can be any valid C++ data type. For example, to declare a 10-element array called balance of type double, use this statement −
Double balance[10];
Initializing Arrays
You can initialize C++ array elements either one by one or using a single statement as follows −
Double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
The number of values between braces { } can not be larger than the number of elements that we declare for the array between square brackets [ ]. Following is an example to assign a single element of the array −
If you omit the size of the array, an array just big enough to hold the initialization is created. Therefore, if you write −
Double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
You will create exactly the same array as you did in the previous example.
Balance[4] = 50.0;
The above statement assigns element number 5th in the array a value of 50.0. Array with 4th index will be 5th, i.e., last element because all arrays have 0 as the index of their first element which is also called base index. Following is the pictorial representaion of the same array we discussed above −
Accessing Array Elements
An element is accessed by indexing the array name. This is done by placing the index of the element within square brackets after the name of the array. For example −
Double salary = balance[9];
The above statement will take 10th element from the array and assign the value to salary variable. Following is an example, which will use all the above-mentioned three concepts viz. Declaration, assignment and accessing arrays −
#include <iostream>
Using namespace std;
#include <iomanip>
Using std::setw;
Int main () {
Int n[ 10 ]; // n is an array of 10 integers
// initialize elements of array n to 0
For ( int i = 0; i < 10; i++ ) {
n[ i ] = i + 100; // set element at location i to i + 100
}
Cout << "Element" << setw( 13 ) << "Value" << endl;
// output each array element's value
For ( int j = 0; j < 10; j++ ) {
Cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
}
Return 0;
}
This program makes use of setw() function to format the output. When the above code is compiled and executed, it produces the following result −
Element Value
0 100
1 101
2 102
3 103
4 104
5 105
6 106
7 107
8 108
9 109
Arrays in C++
Arrays are important to C++ and should need lots of more detail. There are following few important concepts, which should be clear to a C++ programmer −
Sr.No | Concept & Description |
1 | Multi-dimensional arrays C++ supports multidimensional arrays. The simplest form of the multidimensional array is the two-dimensional array. |
2 | Pointer to an array You can generate a pointer to the first element of an array by simply specifying the array name, without any index. |
3 | Passing arrays to functions You can pass to the function a pointer to an array by specifying the array's name without an index. |
4 | Return array from functions C++ allows a function to return an array. |
KEY TAKEAWAY
C++ provides a data structure, the array, which stores a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type.
References:
1. E Balagurusamy, “Programming with C++”, Tata McGraw Hill, 3rd Edition.
2. Herbert Schildt, “The Complete Reference C++”, 4th Edition.
3. Robert Lafore, “Object Oriented Programming in C++”, Sams Publishing, 4th Edition.
4. Matt Weisfeld, “The Object-Oriented Thought Process”, Pearson Education.