UNIT 4
Classes and Data Abstraction
In C++, classes and structs are blueprints that are used to create the instance of a class. Structs are used for lightweight objects such as Rectangle, color, Point, etc.
Unlike class, structs in C++ are value type than reference type. It is useful if you have data that is not intended to be modified after creation of struct.
C++ Structure is a collection of different data types. It is similar to the class that holds different types of data.
The Syntax Of Structure
- Struct structure_name
- {
- // member declarations.
- }
In the above declaration, a structure is declared by preceding the struct keyword followed by the identifier(structure name). Inside the curly braces, we can declare the member variables of different types. Consider the following situation:
- Struct Student
- {
- Char name[20];
- Int id;
- Int age;
- }
In the above case, Student is a structure contains three variables name, id, and age. When the structure is declared, no memory is allocated. When the variable of a structure is created, then the memory is allocated. Let's understand this scenario.
How to create the instance of Structure?
Structure variable can be defined as:
Student s;
Here, s is a structure variable of type Student. When the structure variable is created, the memory will be allocated. Student structure contains one char variable and two integer variable. Therefore, the memory for one char variable is 1 byte and two ints will be 2*4 = 8. The total memory occupied by the s variable is 9 byte.
How to access the variable of Structure:
The variable of the structure can be accessed by simply using the instance of the structure followed by the dot (.) operator and then the field of the structure.
For example:
- s.id = 4;
In the above statement, we are accessing the id field of the structure Student by using the dot(.) operator and assigns the value 4 to the id field.
C++ Struct Example
Let's see a simple example of struct Rectangle which has two data members width and height.
- #include <iostream>
- Using namespace std;
- Struct Rectangle
- {
- Int width, height;
- };
- Int main(void) {
- Struct Rectangle rec;
- Rec.width=8;
- Rec.height=5;
- Cout<<"Area of Rectangle is: "<<(rec.width * rec.height)<<endl;
- Return 0;
- }
Output:
Area of Rectangle is: 40
C++ Struct Example: Using Constructor and Method
Let's see another example of struct where we are using the constructor to initialize data and method to calculate the area of rectangle.
- #include <iostream>
- Using namespace std;
- Struct Rectangle {
- Int width, height;
- Rectangle(int w, int h)
- {
- Width = w;
- Height = h;
- }
- Void areaOfRectangle() {
- Cout<<"Area of Rectangle is: "<<(width*height); }
- };
- Int main(void) {
- Struct Rectangle rec=Rectangle(4,6);
- Rec.areaOfRectangle();
- Return 0;
- }
Output:
Area of Rectangle is: 24
Structure v/s Class
Structure | Class |
If access specifier is not declared explicitly, then by default access specifier will be public. | If access specifier is not declared explicitly, then by default access specifier will be private. |
Syntax of Structure: | Syntax of Class: |
The instance of the structure is known as "Structure variable". | The instance of the class is known as "Object of the class". |
Since C++ is an object-oriented language, program is designed using objects and classes in C++.
C++ Object
In C++, Object is a real world entity, for example, chair, car, pen, mobile, laptop etc.
In other words, object is an entity that has state and behavior. Here, state means data and behavior means functionality.
Object is a runtime entity, it is created at runtime.
Object is an instance of a class. All the members of the class can be accessed through object.
Let's see an example to create object of student class using s1 as the reference variable.
- Student s1; //creating an object of Student
In this example, Student is the type and s1 is the reference variable that refers to the instance of Student class.
C++ Class
In C++, object is a group of similar objects. It is a template from which objects are created. It can have fields, methods, constructors etc.
Let's see an example of C++ class that has three fields only.
- Class Student
- {
- Public:
- Int id; //field or data member
- Float salary; //field or data member
- String name;//field or data member
- }
C++ Object and Class Example
Let's see an example of class that has two fields: id and name. It creates instance of the class, initializes the object and prints the object value.
- #include <iostream>
- Using namespace std;
- Class Student {
- Public:
- Int id;//data member (also instance variable)
- String name;//data member(also instance variable)
- };
- Int main() {
- Student s1; //creating an object of Student
- s1.id = 201;
- s1.name = "Sonoo Jaiswal";
- Cout<<s1.id<<endl;
- Cout<<s1.name<<endl;
- Return 0;
- }
Output:
201
Sonoo Jaiswal
C++ Class Example: Initialize and Display data through method
Let's see another example of C++ class where we are initializing and displaying object through method.
- #include <iostream>
- Using namespace std;
- Class Student {
- Public:
- Int id;//data member (also instance variable)
- String name;//data member(also instance variable)
- Void insert(int i, string n)
- {
- Id = i;
- Name = n;
- }
- Void display()
- {
- Cout<<id<<" "<<name<<endl;
- }
- };
- Int main(void) {
- Student s1; //creating an object of Student
- Student s2; //creating an object of Student
- s1.insert(201, "Sonoo");
- s2.insert(202, "Nakul");
- s1.display();
- s2.display();
- Return 0;
- }
Output:
201 Sonoo
202 Nakul
C++ Class Example: Store and Display Employee Information
Let's see another example of C++ class where we are storing and displaying employee information using method.
- #include <iostream>
- Using namespace std;
- Class Employee {
- Public:
- Int id;//data member (also instance variable)
- String name;//data member(also instance variable)
- Float salary;
- Void insert(int i, string n, float s)
- {
- Id = i;
- Name = n;
- Salary = s;
- }
- Void display()
- {
- Cout<<id<<" "<<name<<" "<<salary<<endl;
- }
- };
- Int main(void) {
- Employee e1; //creating an object of Employee
- Employee e2; //creating an object of Employee
- e1.insert(201, "Sonoo",990000);
- e2.insert(202, "Nakul", 29000);
- e1.display();
- e2.display();
- Return 0;
- }
Output:
201 Sonoo 990000
202 Nakul 29000
C++ allows you to specify more than one definition for a function name or an operator in the same scope, which is called function overloading and operator overloading respectively.
An overloaded declaration is a declaration that is declared with the same name as a previously declared declaration in the same scope, except that both declarations have different arguments and obviously different definition (implementation).
When you call an overloaded function or operator, the compiler determines the most appropriate definition to use, by comparing the argument types you have used to call the function or operator with the parameter types specified in the definitions. The process of selecting the most appropriate overloaded function or operator is called overload resolution.
Function Overloading in C++
You can have multiple definitions for the same function name in the same scope. The definition of the function must differ from each other by the types and/or the number of arguments in the argument list. You cannot overload function declarations that differ only by return type.
Following is the example where same function print() is being used to print different data types –
#include <iostream>
Using namespace std;
Class printData {
Public:
Void print(int i) {
Cout << "Printing int: " << i << endl;
}
Void print(double f) {
Cout << "Printing float: " << f << endl;
}
Void print(char* c) {
Cout << "Printing character: " << c << endl;
}
};
Int main(void) {
PrintData pd;
// Call print to print integer
Pd.print(5);
// Call print to print float
Pd.print(500.263);
// Call print to print character
Pd.print("Hello C++");
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
Operators Overloading in C++
You can redefine or overload most of the built-in operators available in C++. Thus, a programmer can use operators with user-defined types as well.
Overloaded operators are functions with special names: the keyword "operator" followed by the symbol for the operator being defined. Like any other function, an overloaded operator has a return type and a parameter list.
Box operator+(const Box&);
Declares the addition operator that can be used to add two Box objects and returns final Box object. Most overloaded operators may be defined as ordinary non-member functions or as class member functions. In case we define above function as non-member function of a class then we would have to pass two arguments for each operand as follows −
Box operator+(const Box&, const Box&);
Following is the example to show the concept of operator over loading using a member function. Here an object is passed as an argument whose properties will be accessed using this object, the object which will call this operator can be accessed using this operator as explained below –
#include <iostream>
Using namespace std;
Class Box {
Public:
Double getVolume(void) {
Return length * breadth * height;
}
Void setLength( double len ) {
Length = len;
}
Void setBreadth( double bre ) {
Breadth = bre;
}
Void setHeight( double hei ) {
Height = hei;
}
// Overload + operator to add two Box objects.
Box operator+(const Box& b) {
Box box;
Box.length = this->length + b.length;
Box.breadth = this->breadth + b.breadth;
Box.height = this->height + b.height;
Return box;
}
Private:
Double length; // Length of a box
Double breadth; // Breadth of a box
Double height; // Height of a box
};
// Main function for the program
Int main() {
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
Box Box3; // Declare Box3 of type Box
Double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
Volume = Box1.getVolume();
Cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
Volume = Box2.getVolume();
Cout << "Volume of Box2 : " << volume <<endl;
// Add two object as follows:
Box3 = Box1 + Box2;
// volume of box 3
Volume = Box3.getVolume();
Cout << "Volume of Box3 : " << volume <<endl;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
Overloadable/Non-overloadableOperators
Following is the list of operators which can be overloaded −
+ | - | * | / | % | ^ |
& | | | ~ | ! | , | = |
< | > | <= | >= | ++ | -- |
<< | >> | == | != | && | || |
+= | -= | /= | %= | ^= | &= |
|= | *= | <<= | >>= | [] | () |
-> | ->* | New | New [] | Delete | Delete [] |
Following is the list of operators, which can not be overloaded −
:: | .* | . | ?: |
Operator Overloading Examples
Here are various operator overloading examples to help you in understanding the concept.
Sr.No | Operators & Example |
1 | Unary Operators Overloading |
2 | Binary Operators Overloading |
3 | Relational Operators Overloading |
4 | Input/Output Operators Overloading |
5 | ++ and -- Operators Overloading |
6 | Assignment Operators Overloading |
7 | Function call () Operator Overloading |
8 | Subscripting [] Operator Overloading |
9 | Class Member Access Operator -> Overloading |
You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor.
Following example explains how an assignment operator can be overloaded.
#include <iostream>
Using namespace std;
Class Distance {
Private:
Int feet; // 0 to infinite
Int inches; // 0 to 12
Public:
// required constructors
Distance() {
Feet = 0;
Inches = 0;
}
Distance(int f, int i) {
Feet = f;
Inches = i;
}
Void operator = (const Distance &D ) {
Feet = D.feet;
Inches = D.inches;
}
// method to display distance
Void displayDistance() {
Cout << "F: " << feet << " I:" << inches << endl;
}
};
Int main() {
Distance D1(11, 10), D2(5, 11);
Cout << "First Distance : ";
D1.displayDistance();
Cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
Cout << "First Distance :";
D1.displayDistance();
Return 0;
}
When the above code is compiled and executed, it produces the following result −
First Distance : F: 11 I:10
Second Distance :F: 5 I:11
First Distance :F: 5 I:11
A storage class defines the scope (visibility) and life-time of variables and/or functions within a C++ Program. These specifiers precede the type that they modify. There are following storage classes, which can be used in a C++ Program
- Auto
- Register
- Static
- Extern
- Mutable
The auto Storage Class
The auto storage class is the default storage class for all local variables.
{
Int mount;
Auto int month;
}
The example above defines two variables with the same storage class, auto can only be used within functions, i.e., local variables.
The register Storage Class
The register storage class is used to define local variables that should be stored in a register instead of RAM. This means that the variable has a maximum size equal to the register size (usually one word) and can't have the unary '&' operator applied to it (as it does not have a memory location).
{
Register int miles;
}
The register should only be used for variables that require quick access such as counters. It should also be noted that defining 'register' does not mean that the variable will be stored in a register. It means that it MIGHT be stored in a register depending on hardware and implementation restrictions.
The static Storage Class
The static storage class instructs the compiler to keep a local variable in existence during the life-time of the program instead of creating and destroying it each time it comes into and goes out of scope. Therefore, making local variables static allows them to maintain their values between function calls.
The static modifier may also be applied to global variables. When this is done, it causes that variable's scope to be restricted to the file in which it is declared.
In C++, when static is used on a class data member, it causes only one copy of that member to be shared by all objects of its class.
#include <iostream>
// Function declaration
Void func(void);
Static int count = 10; /* Global variable */
Main() {
While(count--) {
Func();
}
Return 0;
}
// Function definition
Void func( void ) {
Static int i = 5; // local static variable
i++;
Std::cout << "i is " << i ;
Std::cout << " and count is " << count << std::endl;
}
When the above code is compiled and executed, it produces the following result −
i is 6 and count is 9
i is 7 and count is 8
i is 8 and count is 7
i is 9 and count is 6
i is 10 and count is 5
i is 11 and count is 4
i is 12 and count is 3
i is 13 and count is 2
i is 14 and count is 1
i is 15 and count is 0
The extern Storage Class
The extern storage class is used to give a reference of a global variable that is visible to ALL the program files. When you use 'extern' the variable cannot be initialized as all it does is point the variable name at a storage location that has been previously defined.
When you have multiple files and you define a global variable or function, which will be used in other files also, then extern will be used in another file to give reference of defined variable or function. Just for understanding extern is used to declare a global variable or function in another file.
The extern modifier is most commonly used when there are two or more files sharing the same global variables or functions as explained below.
First File: main.cpp
#include <iostream>
Int count ;
Extern void write_extern();
Main() {
Count = 5;
Write_extern();
}
Second File: support.cpp
#include <iostream>
Extern int count;
Void write_extern(void) {
Std::cout << "Count is " << count << std::endl;
}
Here, extern keyword is being used to declare count in another file. Now compile these two files as follows −
$g++ main.cpp support.cpp -o write
This will produce write executable program, try to execute write and check the result as follows −
$./write
5
The mutable Storage Class
The mutable specifier applies only to class objects, which are discussed later in this tutorial. It allows a member of an object to override const member function. That is, a mutable member can be modified by a const member function.
A scope is a region of the program and broadly speaking there are three places, where variables can be declared −
- Inside a function or a block which is called local variables,
- In the definition of function parameters which is called formal parameters.
- Outside of all functions which is called global variables.
We will learn what is a function and it's parameter in subsequent chapters. Here let us explain what are local and global variables.
Local Variables
Variables that are declared inside a function or block are local variables. They can be used only by statements that are inside that function or block of code. Local variables are not known to functions outside their own. Following is the example using local variables −
#include <iostream>
Using namespace std;
Int main () {
// Local variable declaration:
Int a, b;
Int c;
// actual initialization
a = 10;
b = 20;
c = a + b;
Cout << c;
Return 0;
}
Global Variables
Global variables are defined outside of all the functions, usually on top of the program. The global variables will hold their value throughout the life-time of your program.
A global variable can be accessed by any function. That is, a global variable is available for use throughout your entire program after its declaration. Following is the example using global and local variables −
#include <iostream>
Using namespace std;
// Global variable declaration:
Int g;
Int main () {
// Local variable declaration:
Int a, b;
// actual initialization
a = 10;
b = 20;
g = a + b;
Cout << g;
Return 0;
}
A program can have same name for local and global variables but value of local variable inside a function will take preference. For example −
#include <iostream>
Using namespace std;
// Global variable declaration:
Int g = 20;
Int main () {
// Local variable declaration:
Int g = 10;
Cout << g;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
10
Initializing Local and Global Variables
When a local variable is defined, it is not initialized by the system, you must initialize it yourself. Global variables are initialized automatically by the system when you define them as follows −
Data Type | Initializer |
Int | 0 |
Char | '\0' |
Float | 0 |
Double | 0 |
Pointer | NULL |
It is a good programming practice to initialize variables properly, otherwise sometimes program would produce unexpected result.
A reference variable is an alias, that is, another name for an already existing variable. Once a reference is initialized with a variable, either the variable name or the reference name may be used to refer to the variable.
References vs Pointers
References are often confused with pointers but three major differences between references and pointers are −
- You cannot have NULL references. You must always be able to assume that a reference is connected to a legitimate piece of storage.
- Once a reference is initialized to an object, it cannot be changed to refer to another object. Pointers can be pointed to another object at any time.
- A reference must be initialized when it is created. Pointers can be initialized at any time.
Creating References in C++
Think of a variable name as a label attached to the variable's location in memory. You can then think of a reference as a second label attached to that memory location. Therefore, you can access the contents of the variable through either the original variable name or the reference. For example, suppose we have the following example −
Int i = 17;
We can declare reference variables for i as follows.
Int& r = i;
Read the & in these declarations as reference. Thus, read the first declaration as "r is an integer reference initialized to i" and read the second declaration as "s is a double reference initialized to d.". Following example makes use of references on int and double −
#include <iostream>
Using namespace std;
Int main () {
// declare simple variables
Int i;
Double d;
// declare reference variables
Int& r = i;
Double& s = d;
i = 5;
Cout << "Value of i : " << i << endl;
Cout << "Value of i reference : " << r << endl;
d = 11.7;
Cout << "Value of d : " << d << endl;
Cout << "Value of d reference : " << s << endl;
Return 0;
}
When the above code is compiled together and executed, it produces the following result −
Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7
References are usually used for function argument lists and function return values. So following are two important subjects related to C++ references which should be clear to a C++ programmer −
Sr.No | Concept & Description |
1 | References as Parameters C++ supports passing references as function parameter more safely than parameters. |
2 | Reference as Return Value You can return reference from a C++ function like any other data type. |
Passing parameters by references
We have discussed how we implement call by reference concept using pointers. Here is another example of call by reference which makes use of C++ reference −
#include <iostream>
Using namespace std;
// function declaration
Void swap(int& x, int& y);
Int main () {
// local variable declaration:
Int a = 100;
Int b = 200;
Cout << "Before swap, value of a :" << a << endl;
Cout << "Before swap, value of b :" << b << endl;
/* calling a function to swap the values.*/
Swap(a, b);
Cout << "After swap, value of a :" << a << endl;
Cout << "After swap, value of b :" << b << endl;
Return 0;
}
// function definition to swap the values.
Void swap(int& x, int& y) {
Int temp;
Temp = x; /* save the value at address x */
x = y; /* put y into x */
y = temp; /* put x into y */
Return;
}
When the above code is compiled and executed, it produces the following result −
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100
Returning values 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
}
A member function of a class is a function that has its definition or its prototype within the class definition like any other variable. It operates on any object of the class of which it is a member, and has access to all the members of a class for that object.
Let us take previously defined class to access the members of the class using a member function instead of directly accessing them −
Class Box {
Public:
Double length; // Length of a box
Double breadth; // Breadth of a box
Double height; // Height of a box
Double getVolume(void);// Returns box volume
};
Member functions can be defined within the class definition or separately using scope resolution operator, : −. Defining a member function within the class definition declares the function inline, even if you do not use the inline specifier. So either you can define Volume() function as below −
Class Box {
Public:
Double length; // Length of a box
Double breadth; // Breadth of a box
Double height; // Height of a box
Double getVolume(void) {
Return length * breadth * height;
}
};
If you like, you can define the same function outside the class using the scope resolution operator (::) as follows −
Double Box::getVolume(void) {
Return length * breadth * height;
}
Here, only important point is that you would have to use class name just before :: operator. A member function will be called using a dot operator (.) on a object where it will manipulate data related to that object only as follows −
Box myBox; // Create an object
MyBox.getVolume(); // Call member function for the object
Let us put above concepts to set and get the value of different class members in a class −
#include <iostream>
Using namespace std;
Class Box {
Public:
Double length; // Length of a box
Double breadth; // Breadth of a box
Double height; // Height of a box
// Member functions declaration
Double getVolume(void);
Void setLength( double len );
Void setBreadth( double bre );
Void setHeight( double hei );
};
// Member functions definitions
Double Box::getVolume(void) {
Return length * breadth * height;
}
Void Box::setLength( double len ) {
Length = len;
}
Void Box::setBreadth( double bre ) {
Breadth = bre;
}
Void Box::setHeight( double hei ) {
Height = hei;
}
// Main function for the program
Int main() {
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
Double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
Volume = Box1.getVolume();
Cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
Volume = Box2.getVolume();
Cout << "Volume of Box2 : " << volume <<endl;
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Volume of Box1 : 210
Volume of Box2 : 1560
Let’s provide some functionality that should natural to fractions. We will want to multiply fractions at some point, so let’s define a non-member function that will get the job done for us.
// in the Fractions.cpp file
Fraction mult_fracs(const Fraction & lhs, const Fraction & rhs)
{
Fraction temp; // a fraction to build locally and then return
temp.m_Numerator = lhs.m_Numerator * rhs.m_Numerator;
****** STOP – THIS WON’T COMPILE !! ********
In this code we have attempted a cardinal sin, and it won’t compile. In this last line of code, we have tried to access directly the private member variables of Fraction objects. But we did that in the last lesson, you say! Yes, but those were member functions. The function above is a non-member (or global) function. How do deal with this issue then? There are two approaches.
A note before we go on: You will notice that I named the parameters oddly. Lhs and rhs are short for left-hand side and right-hand side, common names for parameters to binary operations. Also, I made them reference parameters so as to avoid the overhead of copying Fraction type objects into the parameters. This is a common practice with user-defined types, which can possibly be large aggregates, thus causing undue overhead.
Accessor and Mutator Functions
Accessor and mutator functions (a.k.a. Set and get functions) provide a direct way to change or just access private variables. They must be written with the utmost care because they have to provide the protection of the data that gives meaning to a class in the first place. Remember the central theme of a class: data members are hidden in the private section, and can only be changed by the public member functions which dictate allowable changes. Let’s see how we might code up these functions for our example class.
Class Fraction
{
public:
void readin();
void print();
Fraction reciprocal();
void unreduced(const int multiplier);
int getNum(); // accessor or get function
int getDen(); // likewise
void setNumer(const int numer); // mutator or set function
bool setDenom(const int denom); // likewise
private:
int m_Numerator;
int m_Denominator;
};
...and here are the definitions:
// these would go in the Fraction.cpp file
int Fraction::getNumer()
{
return m_Numerator;
}
int Fraction::getDenom()
{
return m_Denominator;
}
void Fraction::setNumer(const int numer)
{
m_Numerator = numer;
return;
}
bool Fraction::setDenom(const int denom)
{
bool set = false;
if (denom != 0) // prohibits setting denominator to zero!
{
set = true;
m_Denominator = denom;
}
return set;
}
Now you see that all of these functions are straight forward. The get functions will return the values of the members and the set functions will set the values of the members. Let’s analyze how we defined these. The gets are obvious: return the appropriate value. But let me show you how you might want to write such an obvious function. You can “inline” them into the class definition:
Class Fraction
{
public:
...
int getNumer() {return m_Numerator;}
int getDenom() {return m_Denominator;}
...
}
With quite obvious and simple functions, this acceptable and you are giving away nothing.
As for the set functions, we see that we are able to set the numerator to anything. And that makes sense; a numerator can be any integer, including zero. However, it’s different with the value for the denominator. We mustn’t let the denominator be set to zero. There are many ways to code this, and you will learn all about exception handling in cs 153, which is probably the best way to handle it. However, not knowing that technique, I have chosen to do the above. I have the setDenom function return a bool to represent whether or not the value of the denominator was set or not. Let’s see how we might use these functions now back in the example I started at the beginning of this lesson.
// in the Fractions.cpp file
Fraction mult_fracs(const Fraction & lhs, const Fraction & rhs)
{
Fraction temp; // a fraction to build locally and then return
temp.setNumer(lhs.getNumer() * rhs.getNumer());
if (! (temp.setDenom(lhs.getDenom() * rhs.getDenom()))
{ //if set returns true, denom is set, all ok
cout<<"ERROR: denominator is 0 "<<endl; // if set returns false, denom not set
exit(2); // and program bombs
}
return temp;
}
If the argument to the setDenom() function were to be zero, the program would output a message and then exit. Of course, in this case, some fraction’s denominator would have to be zero for this to happen, which we hope could not happen. Well, the way we have the readin() written at this point, it is well possible! We need to rewrite that function:
In general, just because you can write a set or get function for a private member variable, that does not imply that you should. You should only write these functions if they are warranted. Let’s consider an example. Suppose you write a program for keeping grades for a course. You have to write a “student” class. Member variables include an array of quiz grades, an average, and a letter grade. You will have public member functions that include void calc_grade(). When called, this function’s responsibility is to average the quiz scores, set the average member, and then set the letter grade based on that average. This last exercise might be implemented by the calc_grade() function call a compute_grade() function that sets the letter grade based on average. In any case, is it reasonable to have a public setAverage() function? I think not. It isn’t reasonable to be able to set the average arbitrarily to, say, 65 when the quiz grades would indicate an average of 90!
What is constructor?
A constructor is a member function of a class which initializes objects of a class. In C++, Constructor is automatically called when object(instance of class) create. It is special member function of the class.
How constructors are different from a normal member function?
A constructor is different from normal functions in following ways:
- Constructor has same name as the class itself
- Constructors don’t have return type
- A constructor is automatically called when an object is created.
- If we do not specify a constructor, C++ compiler generates a default constructor for us (expects no parameters and has an empty body).
Types of Constructors
- Default Constructor: Default constructor is the constructor which doesn’t take any argument. It has no parameters.
// Cpp program to illustrate the // concept of Constructors #include <iostream> Using namespace std;
Class construct { Public: Int a, b;
// Default Constructor Construct() { a = 10; b = 20; } };
Int main() { // Default constructor called automatically // when the object is created Construct c; Cout << "a: " << c.a << endl << "b: " << c.b; Return 1; } |
Output:
a: 10
b: 20
Note: Even if we do not define any constructor explicitly, the compiler will automatically provide a default constructor implicitly.
- Parameterized Constructors: It is possible to pass arguments to constructors. Typically, these arguments help initialize an object when it is created. To create a parameterized constructor, simply add parameters to it the way you would to any other function. When you define the constructor’s body, use the parameters to initialize the object.
// CPP program to illustrate // parameterized constructors #include <iostream> Using namespace std;
Class Point { Private: Int x, y;
Public: // Parameterized Constructor Point(int x1, int y1) { x = x1; y = y1; }
Int getX() { Return x; } Int getY() { Return y; } };
Int main() { // Constructor called Point p1(10, 15);
// Access values assigned by constructor Cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();
Return 0; } |
Output:
p1.x = 10, p1.y = 15
When an object is declared in a parameterized constructor, the initial values have to be passed as arguments to the constructor function. The normal way of object declaration may not work. The constructors can be called explicitly or implicitly.
Example e = Example(0, 50); // Explicit call
Example e(0, 50); // Implicit call
Uses of Parameterized constructor:
- It is used to initialize the various data elements of different objects with different values when they are created.
- It is used to overload constructors.
Can we have more than one constructors in a class?
Yes, It is called Constructor Overloading.
2. Copy Constructor: A copy constructor is a member function which initializes an object using another object of the same class. Detailed article on Copy Constructor.
Whenever we define one or more non-default constructors( with parameters ) for a class, a default constructor( without parameters ) should also be explicitly defined as the compiler will not provide a default constructor in this case. However, it is not necessary but it’s considered to be the best practice to always define a default constructor.
// Illustration #include "iostream" Using namespace std;
Class point { Private: Double x, y;
Public: // Non-default Constructor & default Constructor Point (double px, double py) { x = px, y = py; } };
Int main(void) { // Define an array of size 10 & of type point // This line will cause error Point a[10];
// Remove above line and program will compile without error Point b = point(5, 6); } |
Output:
Error: point (double px, double py): expects 2 arguments, 0 provided
Default Constructors
Constructors are functions of a class that are executed when new objects of the class are created. The constructors have the same name as the class and no return type, not even void. They are primarily useful for providing initial values for variables of the class. The two main types of constructors are default constructors and parameterized constructors.
Default constructors do not take any parameters. If a default constructor is not provided by the programmer explicitly, then the compiler provides a implicit default constructor. In that case, the default values of the variables are 0.
A program that demonstrates default constructors is given as follows.
Example
#include <iostream>
Using namespace std;
Class DemoDC {
Private:
Int num1, num2 ;
Public:
DemoDC() {
Num1 = 10;
Num2 = 20;
}
Void display() {
Cout<<"num1 = "<< num1 <<endl;
Cout<<"num2 = "<< num2 <<endl;
}
};
Int main() {
DemoDC obj;
Obj.display();
Return 0;
}
Output
Num1 = 10
Num2 = 20
In the above program, the class DemoDC contains a default constructor that initialises num1 and num2 as 10 and 20. It also contains a function display() that prints the value of num1 and num2. The code snippet for this is given as follows.
Class DemoDC {
Private:
Int num1, num2
Public:
DemoDC() {
Num1 = 10;
Num2 = 20;
}
Void display() {
Cout<<"num1 = "<< num1 <<endl;
Cout<<"num2 = "<< num2 <<endl;
}
};
The function main() contains the object definition for an object of class type DemoDC. Then the function display() is called. This is shown below.
DemoDC obj;
Obj.display();
Destructors in C++ are members functions in a class that delete an object. They are called when the class object goes out of scope such as when the function ends, the program ends, a delete variable is called etc.
Destructors are different from normal member functions as they don’t take any argument and don’t return anything. Also, destructors have the same name as their class and their name is preceded by a tilde(~).
A program that demonstrates destructors in C++ is given as follows.
Example
#include<iostream>
Using namespace std;
Class Demo {
Private:
Int num1, num2;
Public:
Demo(int n1, int n2) {
Cout<<"Inside Constructor"<<endl;
Num1 = n1;
Num2 = n2;
}
Void display() {
Cout<<"num1 = "<< num1 <<endl;
Cout<<"num2 = "<< num2 <<endl;
}
~Demo() {
Cout<<"Inside Destructor";
}
};
Int main() {
Demo obj1(10, 20);
Obj1.display();
Return 0;
}
Output
Inside Constructor
Num1 = 10
Num2 = 20
Inside Destructor
In the above program, the class Demo contains a parameterized constructor that initializes num1 and num2 with the values provided by n1 and n2. It also contains a function display() that prints the value of num1 and num2. There is also a destructor in Demo that is called when the scope of the class object is ended. The code snippet for this is given as follows.
Class Demo {
Private:
Int num1, num2;
Public:
Demo(int n1, int n2) {
Cout<<"Inside Constructor"<<endl;
Num1 = n1;
Num2 = n2;
}
Void display() {
Cout<<"num1 = "<< num1 <<endl;
Cout<<"num2 = "<< num2 <<endl;
}
~Demo() {
Cout<<"Inside Destructor";
}
};
The function main() contains the object definition for an object of class type Demo. Then the function display() is called. This is shown below.
Demo obj1(10, 20);
Obj1.display();
Reference Books
1 “Thinking in C++”, Volume 1 and 2 by Bruce Eckel, Chuck Allison, Pearson
Education
2 “Mastering C++”, 1/e by Venugopal, TataMcGraw Hill.
3 “Object Oriented Programming with C++”, 3/e by E. Balaguruswamy, Tata
McGraw Hill.
4 “Starting Out with Object Oriented Programming in C++”, by Tony Gaddis,
Wiley India.