0% found this document useful (0 votes)
5 views24 pages

Object-Oriented Programming Basics

Uploaded by

akshatsinghdhruv
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views24 pages

Object-Oriented Programming Basics

Uploaded by

akshatsinghdhruv
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Lecture Notes

Object Oriented Programming


BEI 2081

3 Objects & Classes

3.1 Introduction

Classes form the basis of object-oriented programming. Classes provide a tool for creating new
data types called abstract data types that can be used as conveniently as built-in types. A class is
a user-defined data type like a structure in C. A class encapsulates both data and functions that
operate on the data into a single unit. Member functions define the operations on data members
and provide access to the class. Objects are the variables or instances of classes.

3.2 Class Definition

A class definition is syntactically similar to a structure definition. Classes contain both data and
functions. The class members (data and functions) are normally grouped into sections private,
public or protected, called access specifiers or visibility levels. The private members are not visible
from outside the class whereas public members are visible anywhere from the program. There is
also another access specifier protected which will be discussed later. In absence of access specifiers,
members will be private by default.

Syntax:

class class_name {
private:
data_type data1;
//......
public:
return_type function_name(data_type arg_list);
//......
};

3.3 Object Declaration and Member Access

The objects of the class can be declared similar to the variable declaration. Let’s see an example
of a program with a simple class.

Example:
class test {
private:
int data1;
int data2;
public:
void setdata(int d1, int d2) {
data1 = d1; // functions defined inside the class are treated inline
data2 = d2;
}
void showdata() {
cout << "Data member 1 = " << data1 << endl;
cout << "Data member 2 = " << data2 << endl;
}
};

int main() {
test t1, t2; // t1.data1 -> error
[Link](101, 102);
[Link](201, 202);
cout << "\nObject 1 Data:" << endl;
[Link]();
cout << "\nObject 2 Data:" << endl;
[Link]();
return 0;
}

The data members of the object are accessed using the member access operator (.) as
object [Link] member name;
The function members of the object can be accessed as
object [Link] function name(arguments...);

3.4 Defining Functions Outside the Class

The member function of a class can also be defined outside the class definition.

Syntax:

class class_name {
public:
return_type member_function(params...);
};

return_type class_name::member_function(params...) {
// function body
}

2
In the above example, member functions are defined inside the class but they can also be defined
outside the class as follows:

void test::setdata(int d1, int d2) {


data1 = d1; // Functions defined outside the class definition are not inline
data2 = d2;
}

void test::showdata() {
cout << "Data member 1 = " << data1 << endl;
cout << "Data member 2 = " << data2 << endl;
}

class test {
private:
int data1;
int data2;
public:
void setdata(int d1, int d2);
void showdata();
};

The functions defined outside the class definition are not inline(in contrast to functions defined
within the class, which are inline by default). To make such functions inline we have to prefix the
keyword inline in front of the function header as:

inline void test::showdata() {


cout << "data1 = " << data1 << endl;
cout << "data2 = " << data2 << endl;
}

3.5 A Physical Object Example

A more practical example that represents a physical object is:

class product {
private:
int productid;
char name[15];
float cost;
public:
void setdata(int pid, char pname[], float cst) {
productid = pid;
strcpy(name, pname); // name = pname does not work!;

3
cost = cst;
}
void showdata() {
cout << "Product ID: " << productid << endl;
cout << "Name: " << name << endl;
cout << "Cost: " << cost << endl;
}
};

int main() {
product p1, p2;
[Link](944, "CD-ROM ", 1500.00);
[Link](945, "Pen Drive", 1000.00);
[Link]();
[Link]();
return 0;
}

3.6 A Mathematical Data as Object Example

An example of a program that uses mathematical data as an object:

class complex {
private:
float real;
float imag;
public:
void readvalue() {
cout << "Enter Real part: "; cin >> real;
cout << "Enter Imaginary part: "; cin >> imag;
}
void showvalue() {
cout << "(" << real << "," << imag << ")";
}
void cadd(complex cn1, complex cn2) {
real = [Link] + [Link];
imag = [Link] + [Link];
}
};

int main() {
complex c1, c2, c3;
cout << "Enter first complex number: " << endl;
[Link]();
cout << "\nEnter second complex number: " << endl;
[Link]();

4
[Link]();
cout << " + ";
[Link]();
[Link](c1, c2);
cout << " = ";
[Link]();
return 0;
}

3.7 Returning Objects from Functions

An example that returns objects from a function is as follows:

class complex {
private:
float real, imag;
public:
void setvalue(float re, float im) {
real = re;
imag = im;
}
void showvalue() {
cout << "(" << real << "," << imag << ")";
}
complex cadd(complex cn) {
complex res;
[Link] = real + [Link];
[Link] = imag + [Link];
return res;
}
};

int main() {
complex c1, c2, c3;
[Link](2.4, 7.5);
[Link](3.2, 5.6);
c3 = [Link](c2);
cout << "\nComplex num1 = "; [Link]();
cout << "\nComplex num2 = "; [Link]();
cout << "\nComplex num3 = "; [Link]();
return 0;
}

5
3.8 Relation of Object, Class and Memory

The creation of a class develops a template for object creation but does not allocate memory. It is
known that objects contain data and functions together, so when objects are created, memory space
is allocated for each member of the objects. This mental model helps in programming, assisting
in understanding abstraction mechanisms. However, in reality, memory is allocated only for data
members but not for function members.

Figure 1: Relationship of Object and Class memory

3.9 Constructor

The class feature in C++ provides special member functions that are automatically invoked when
objects are created. So constructors can be used for the necessary initialization or startup actions
for the objects.

A constructor

• Is member function that has same name as the class

• Does not have return type

6
• Invoked automatically during object creation

• Can be overloaded for different ways of startup/initialization

• Cannot be invoked explicitly other than creating objects

The constructor is made as follows:

class class_name
{
private:
//...
public:
class_name(); //constructor function
//...
};

The constructor is created as follows:

class counter
{
private:
unsigned count;
public:
counter() {count=0;} //default constructor
counter(unsigned n) {count=n;}
//parameterized constructor
void inc(){count++;}
int val(){return count;}
};

The constructors are used as follows:

int main()
{
counter c1,c2(5); //[Link]=0, [Link]=5
cout<<"\nCounter values before increment:";
cout<<"\n Counter 1="<<[Link]();
//c1=0
cout<<"\n Counter 2="<<[Link]();
//c2=5
[Link]();
[Link]();
[Link]();
cout<<"\nCounter values after increment:";
cout<<"\n Counter 1="<<[Link]();

7
//c1=2
cout<<"\n Counter 2="<<[Link]();
//c2=6
}

The constructors without parameter are called default constructors. The constructors with pa-
rameter(s) are called parameterized constructors. Even when we do not define any constructor
in a class a constructor is implicitly defined by the compiler The compiler generated default con-
structor does nothing except calling default constructor of base class or default constructors of
object members.

The default constructor counter::counter() is called when creating object of the class counter with-
out supplying arguments as:

counter c1;

The parameterized constructor are called when creating objects by passing arguments as:

counter c1(2); // You can do something similar in basic data types: int a(5); int a=int();

The behavior of default constructor can also be performed by a parameterized constructor with the
default value as:

class counter
{
private:
unsigned count;
public:
counter(unsigned n=0){count=n;}
//......
};

This constructor serves as a default and parameterized constructor.

Instead of assigning the data members of a class in the body of the constructor we can also initialize
the members through the member initializer list as

class counter
{
private:
unsigned count;
public:
counter():count(0){}
counter (unsigned n):count(n){}
//......
};

8
To initialize multiple members through the member initializer list the members are separated by
comma as

class cname
{
private:
int data1;
int data2;
public:
cname():data1(0),data2(0){}
cname (int n1, int n2):data1(n1),data2(n2){}
//......
};

A single parameter constructor is invoked as

counter c1=5; //counter c1=counter(5);

For const and reference members one must provide the constructor because they must be initialized
and the compiler generated default constructor does not work. For example

class test
{
const int n;
int &r;
};
test t;//error

The correct form is:

int num=5;
class test
{
const int n;
int &r;
public:
test():n(0),r(num){}
test(int a,int &b):n(a),r(b) {}
};
test t; //ok
test t2(2,num); //ok

Note: Constant and reference members must be initialized through initializer list.

Important: When we declare at least one constructor the compiler will not generate the default
constructor.

9
class test
{
private:
int data;
public:
test(int n){data=n;}//parameterized constructor
//......
};
test t1; //error no default constructor
test t2(5) //ok, parameterized constructor is called

To be safe we must declare the default constructor if we have parameterized constructor as:

class test
{
private:
int data;
public:
test(){} //default constructor
test(int n){data=n;}//parameterized constructor
//......
};
test t1; //ok, user defined default constructor is called
test t2(5); //ok, parameterized constructor is called

3.10 Copy Constructor

Objects can also be initialized by another object of its own type as:

Test t1(5); // invokes one parameter constructor


Test t2(t1); // initialize t2 with the value of t1
Test t3 = t1; // initialize t3 with the value of t1

Here, in the second and third cases, an implicitly generated constructor that takes an object of its
own type is called. The constructor that takes an object of its own type as its argument is called
a copy constructor. The default behavior of the implicitly generated copy constructor is that it
copies each member one by one, similar to assigning one structure (object) to another.

If the programmer needs to do something different from the default behavior of the implicitly
generated copy constructor, then one can override it.

The copy constructor is defined as:

class test {

10
private:
//......
public:
test() {}
test(params...) { ... }
test(test &t) { ... } // copy constructor
};

The copy constructor is invoked in the following cases:

test t1;
test t2(t1); // copy constructor called
test t3 = t1; // copy constructor invocation

But assignment will not call the copy constructor:

t3 = t2; // assignment, not initialization

test t4 = t3; // object creation and initialization


// copy constructor invocation

The class with a copy constructor is defined as:

class counter {
private:
unsigned count;
public:
counter(int n = 0) { count = n; }
counter(counter &c) {
count = [Link];
cout << "Copy Constructor Invoked";
}
void inc() { count++; }
int val() { return count; }
};

This copy constructor can be used as:

int main() {
counter c1(5), c4;
counter c2(c1); // Copy constructor called
counter c3 = c1; // Copy constructor invoked
c4 = c1; // assignment, no copy constructor called

11
cout << "\nCounter values before increment:";
cout << "\n Counter 1=" << [Link](); // c1 = 5
cout << "\n Counter 2=" << [Link](); // c2 = 5
cout << "\n Counter 3=" << [Link](); // c3 = 5

[Link]();
[Link]();
[Link]();

cout << "\nCounter values after increment:";


cout << "\n Counter 1=" << [Link](); // c1 = 5
cout << "\n Counter 2=" << [Link](); // c2 = 6
cout << "\n Counter 3=" << [Link](); // c3 = 7

return 0;
}

Note: If a class has reference and const members, then a copy constructor cannot be
created.

3.11 Destructor

Similar to constructors, destructors are special functions. Destructors are invoked when an object
is being destroyed. The destructor’s name is the same as the class name, preceded by a tilde ( )
character. A destructor does not take any arguments and does not return a value. There can
be only one destructor in a class. It is not necessary to define a destructor if final cleanup is
not required. The implicitly generated destructor does nothing except destroying sub-objects or
member objects.

Destructors are normally used to release memory acquired by the constructor or to perform some
other cleanup operation for the object.

Following is the format for declaring the destructor in a class:

class Test {
private:
//......
public:
Test() {} // constructor
~Test() {} // destructor
};

Let’s see the usage of a destructor:

class test {

12
private:
int data;
public:
test() { data = 0; }
test(int n) { data = n; }
~test() { cout << "\object " << data << " destroyed"; }
};

int main() {
test c1, c2(5);
//...
}

When dynamic memory allocation is done, a destructor is used as follows:

class test {
private:
int *arr;
public:
test() {}
test(int n) { arr = new int[n]; }
~test() { delete[] arr; }
};

int main() {
test c2(5); // constructor allocates space for 5 ints
// destructor deallocates allocated space
}

3.12 Class and Structure

In C++, declaring a structure is fundamentally the same as declaring a class. The structure in
C++ can have member functions along with data members in a single unit. Unlike the structures
in C, in C++ they are an alternative way of declaring a class. The only difference between a class
and a structure is that, in a class, members are private by default, whereas in a structure members
are public by default.

When a structure is defined as:

struct s {
int a;
};

It is equivalent to the following class definition:

13
class s {
public:
int a;
};

When a class is defined as:

class s {
int b;
};

It is equivalent to the following structure definition:

struct s {
private:
int b;
};

Normally, structures are used like C structs and classes are used as C++ classes.

3.13 Array of Objects

Like normal variables, we can create an array of objects. For the following class:

class test {
private:
int data;
public:
test() {} // default constructor
test(int n) { data = n; } // parameterized constructor
//......
};

The array of objects can be created as:

test arr[10];

Object arrays can be initialized like basic type arrays if a one-argument constructor is present, as:

test t1[5] = {3, 4, 7, 10, 12};

This initialization is equivalent to:

14
test t1[5] = {test(3), test(4), test(7), test(10), test(12)};

When we have to invoke a two-parameter constructor of the form:

class test {
private:
int data1, data2;
public:
test(int n1, int n2): data1(n1), data2(n2) {}
//......
};

The array initialization list in this case must be specified as follows:

test t3[3] = {test(2, 5), test(7, 9), test(4, 8)};

3.14 Pointer to Objects

Similar to pointers to other standard variables, we can create pointer variables that will hold the
address of an object.

We can declare a pointer to an object as:

class_name *pointer_to_object;
class_name object_name;

The address of an object can be assigned to the pointer variable as:

pointer_to_object = &object_name;

When creating objects dynamically, the object pointer variable is used as:

pointer_to_object = new class_name; // or new class_name[size];


pointer_to_object = new class_name(args...); // constructor called

Through the pointer to object, we can access the object’s members as:

pointer_to_object->member; // equivalent to (*pointer_to_object).member;

15
3.15 The this Pointer

Every C++ object has an implicitly defined pointer of its own type named this that points to
itself. The non-static member functions of every object have access to the magic pointer named
this. Since static functions can be accessed without creating an object, they do not have access
to the this pointer.

Let’s see an example:

class test {
private:
int a;
public:
func1() { ... }
func2() {
cout << this->a;
this->func1();
}
};

This example shows the meaning of the this pointer rather than its usage.

The following example shows practical usage of the this pointer:

class counter {
private:
unsigned count;
public:
counter(int n=0) { count = n; }
counter inc() {
count++;
return *this; // or return counter(count);
}
int val() { return count; }
};

// The statement counter(count) creates a nameless object which is not efficient.


// So the counter::inc() function can be used as:

counter c1, c2(5);


c1 = [Link]();

The counter::inc() function increases the value of the count member of c2 and returns the new
value of c2. Another use can be when returning the greater object among two:

t3 = [Link](t2); // return greater object among t1 and t2

16
3.16 The static Data Members

When a class is instantiated, memory is allocated for the created object, that is, memory is allocated
for each member of the object. There are special types of data members declared as static for
which the memory is not allocated during object creation.

Figure 2: Object and Static member memory.

The static data members belong to the class but not to any particular object. They are declared
in the class and defined outside the class. They are stored separately, common to all the objects,
and shared by all objects of that class. Static members can be used before any object creation or
directly through the class.

Let’s see an example program:

class stTest {
private:
int hdata;
static int hstdata;
public:
static int vstdata;
void setdata(int n1, int n2, int n3) {
hdata = n1;

17
hstdata = n2;
vstdata = n3;
}
void showdata() {
cout << "Private data= " << hdata << endl;
cout << "Private static data= " << hstdata << endl;
cout << "Public static data= " << vstdata << endl;
}
};

int stTest::hstdata; // initialized to zero when not explicitly initialized


int stTest::vstdata = 5;

int main() {
cout << "Public st data from class = " << stTest::vstdata << endl;
stTest::vstdata = 27; // Ok
// stTest::hstdata = 53; // Error, private static member
stTest st1; // [Link] can be done
[Link]();
[Link](12, 15, 17);
stTest st2;
[Link](43, 94, 32);
[Link]();
[Link]();
}

3.17 The static Member Functions

Similar to static data members, static functions belong to a class and not to any object. Static
functions can be called without object creation through the class using the scope resolution operator
as follows:

class_name::static_function();

The static member functions can also be called from objects using the dot (.) operator. Static
member functions can only access static data, so they are useful in accessing private static data.
As static functions can be called before object creation or directly by the class, they cannot access
non-static data members.

Let’s see an example of a static member function:

class element {
private:
static int count;

18
int data;
public:
element() { count++; data = count; }
~element() {
count--;
cout << "Destroying element with value" << data << endl;
}
static void showcount() // static function
{
cout << "Number of elements are:" << count << endl;
}
void showdata()
{
cout << "The data is:" << data << endl;
}
};

int element::count = 0;

int main()
{
element s1;
element::showcount();
element s2, s3;
element::showcount();
[Link]();
[Link]();
[Link]();
return 0;
}

3.18 Constant Member Functions and Constant Objects

We can make member functions in a class that do not alter the values of their data members.
But still, there can be some cases where we accidentally write code that changes the values of
data members. C++ allows us to define member functions that guarantee not to change the data
members’ values (eventually the object’s value) and prevent accidental alteration.

These types of functions that guarantee not to change an object’s value (or data member value) are
called constant member functions. Constant member functions are useful for constant objects.
Constant objects can only call their constant member functions. Constant member functions are
declared by placing the const keyword after the parameter list and before the function body.

Let’s see the following code:

class test {

19
private:
int data;
public:
test() { data = 0; }
test(int n) { data = n; }
void setdata(int n) { data = n; }
void showdata() const {
cout << "data=" << data << endl;
}
};

int main() {
const test t1(5);
test t2(7);
// [Link](9); // Error, calling non constant function
[Link](); // Ok, constant function
[Link](4); // Ok
[Link](); // Ok
return 0;
}

A constant object cannot call a non-constant member function even if it does not alter the values.
A non-constant object can call both constant and non-constant member functions.

3.19 The const cast Operator

In some cases, classes can use data which are used internally for the manipulation of the objects
but are not visible to the user by any means. Changing the value of these members by the constant
function may not change the meaning of the constantness to the user. In rare cases, constant
functions need to change the value of internally used unobservable data members.

ISO C++ provides the keyword const cast operator, which is used in constant functions to remove
the constantness and update those types of members.

Let’s see the example:

class test {
private:
int data1;
int data2; // changeable attribute
public:
test() { data1 = 0; data2 = 0; }
test(int n) { data1 = n; data2 = 0; }
void showdata() const {
test *tp = const_cast<test*>(this);

20
tp->data2 = tp->data2 + 1;
cout << "data=" << data1 << endl;
cout << "func called for " << data2 << " times" << endl;
}
};

int main() {
const test t1(5);
test t2(7);
[Link](); // undefined behavior
[Link](); // Ok
}

The behavior of the const cast operator is undefined if the object itself is declared as const.

3.20 The mutable Class Members

Using the const cast operator, it is possible to remove the constantness of an object or member.
The behavior of const cast is implementation-dependent when the object is declared as constant.

As an alternative to the const cast operator, the data members themselves can be declared as
changeable even within constant functions and for constant objects. ISO C++ provides the keyword
mutable to specify changeable members. A mutable data member is always modifiable even in
constant member functions or constant objects.

So the above code can be written as:

class test {
private:
int data1;
mutable int data2; // changeable attribute
public:
// ...
void showdata() const {
data2 = data2 + 1;
cout << "data=" << data1 << endl;
cout << "func called for " << data2 << " times" << endl;
}
};

3.21 Friend Functions

Private members of an object are not accessible from code outside the class. The private members
can be accessed indirectly through public member functions. Sometimes this feature leads to

21
inconvenience. For example, if we want to use a function to operate on objects of two different
classes, then a function outside a class should be allowed to access and manipulate the private
members of the class. C++ allows us to access the private members of an object through the
concept of friend functions.

To declare that some function is a friend of a class, the function is declared in the class by prefixing
it with the keyword friend. A friend declaration can be placed in either the private or public part
of the class declaration. The function mentioned as a friend of a class can be a global function or
a function in any scope.

class test
{
//......
friend return_type friendfunc(parameters...); // declaration
};

return_type friendfunc(parameters...) { ... } // definition

The friend function can be used as follows:

class test
{
private:
int data;
public:
test(int v=0) { data = v; }
int val() { return data; }
friend void inc(test &a);
};

void inc(test &a) {


[Link]++;
}

int main()
{
test t(4);
cout << "Value before increment: " << [Link]() << endl;
inc(t);
cout << "Value after increment: " << [Link]() << endl;
return 0;
}

Friend functions are also useful when we have to bridge between two classes.

22
3.22 Friend Classes

Similar to friend functions, any class can be a friend of another class. When a class is declared as a
friend of another class, all the member functions of the friend class can access the private members
of the other class. A class can be declared as a friend as follows:

class B;
class A
{
//......
friend class B; // B is declared as friend of A
};

Let’s see an example:

class second;
class first
{
private:
int data;
public:
first(int v=0) { data = v; }
int val() { return data; }
friend class second;
};

class second
{
//...
public:
void inc(first &a) { [Link]++; }
};

int main()
{
first f(5);
second s;
cout << "Value before increment: " << [Link]() << endl;
[Link](f);
cout << "Value after increment: " << [Link]() << endl;
return 0;
}

If class B is declared as friend of class A, then class B can access private members of class A but the
reverse is not true. If both classes need to access each other’s private members, then both classes
have to be declared as friends of one another.

23
Instead of making the whole class a friend, specific member functions of a class can be made friends.

24

You might also like