C++ Programming
CSE225: Data Structures and Algorithms
The Hello Program
#include <iostream>
using namespace std;
int main()
{
char name[100];
cout << "Enter your name: ";
cin >> name; //scanf
cout << "Hello " <<name<<endl; //printf
return 0;
}
C++ has two types of data types:
1. Primitive Data Type:
- Basic Unit of Language
- Each Primitive value is a single datum
Example: int , char, float, etc.
• 2. Composite Data Type:
- Multiple pieces of related data as a single datum
Example: array, structure, class, etc.
** What are the differences between Primitive and Composite Data Types??
Structure
- A linear, direct access data structure with heterogeneous
components
- A component is also called a field or a member
- Each field has its own type
- An identifier is used to name a field/component
Example:
struct CarType {
int year;
char maker[10];
float price;
};
CarType MyCar;//in C++ CarType is considered a data type
//name; unlike C where you have to write struct CarType
Objects & Class
• Object:
• a variable or an instance of a class
OBJECT
set of methods
Operations (public member functions)
Data
internal state
(values of private data members)
Motivation for classes
• Object-Oriented Programming (OOP)
• Package together a set of related data and operations
(encapsulation)
• Allows programmer to define a class (abstract data type)
• One instance (variable) of a class is called an object
• The data and operations of a class are called its members.
A Class & Its Objects
class Rectangle Rectangle r1;
{ Rectangle r2;
Rectangle r3;
private://by default
int width;
int length;
public:
void set(int w, int l);
int area();
};
Define a Class Type
class Rectangle
class class_name {
{ private:
permission_label:
int width;
member;
permission_label: int length;
member; public:
... void set(int w, int l);
};
int area();
};
Another Example
//Circle.cpp file
//Circle.h file // member function definitions
#include <iostream.h> circle::circle(){radius = 0.0;}
void display (double r){
class circle cout << r << endl;
{ }
private:
double radius; void circle:: store(double r){
radius = r;
public: }
circle(); double circle::area(){
void store(double); return 3.14*radius*radius;
double area(); }
void display(); void circle::display(){
}; cout << “r = “ << radius << endl;
void display(double r); }
//main.cpp file
int main(void) {
circle c; // an object of circle class
c.store(5.0); cout << "The area of circle c is " << c.area() << endl;
c.display();
}
Class Definition - Access Control
• Information hiding
• To prevent the internal representation from direct access from outside
the class
• Access Specifiers
• public
• may be accessible from anywhere within a program
• private
• may be accessed only by the member functions, and friends of this
class, not accessible to nonmember functions
• Protected
• Accessible only to derived/child + same class member functions
• Difference between classes and structs in C++
the default access specifier is private in class
the default access specifier is public in struct
Class Definition – Member Functions
• Used to
• access the values of the data members (accessor/get method)
• perform operations on the data members (modifier/set method)
• Are declared inside the class body, in the same way as
declaring a function
• Their definition can be placed inside the class body, or
outside the class body
• Can access both public and private members of the class
• Can be called using dot (for an object) or arrow (for a
pointer to an object) member access operator
Define a Member Function
class Rectangle
{
private:
int width, length;
public:
void set (int w, int l){width=w;length=l;}
int area() {return width*length; }
}
Rectangle r1;
r1.set(5,8);
Rectangle *rp=&r1;
rp -> set(8,10);//equivalent to: r1.set(8,10); or (*rp).set(8,10);
Defining Methods Separately
• For methods/functions that are declared but not defined in the class we
need to provide a separate definition
• To define the method, you define it as any other function, except that
the name of the function is written as:-
ClassName::FuncName
:: is the scope resolution operator, it allows us to refer to parts of a class or
structure
Defining Member Functions
class Rectangle
{
private:
int width, length; class name
public:
void set (int w, int l);
member function name
int area() {return width*length; }
}
void Rectangle :: set (int w, int l)
Rectangle r1;
{
r1.set(5,8);
width = w;
Rectangle *rp; length = l; scope operator
rp->set(8,10);
}
Inline Functions
• In an inline function, the C++ compiler does not make a function call, instead the code of
the function is inserted (in .exe file) in place of the function call (and appropriate argument
substitutions are made)
• Why used?
• It saves the memory space when a function is likely to be called many times (no stack
push happens)
• When we need to make the function call very fast.
• E.g. for accessing/changing fields of a class (set/get methods)
• Compiler replaces the definition of inline functions at compile time instead of referring
function definition at runtime.
• Typically done for simple/small functions; because otherwise exe file will become very
large
• Inline functions’ declaration and definition can’t be split into .h and .cpp files
inline int sum(int a, int b)
{ return a+b; }//inline is a keyword that
//tells the compiler that this
//function is inline
Member Functions defined within class
declaration are automatically inline functions
class Rectangle
{
private:
int width, length;
public:
void set (int w, int l);
int area() {return width*length; }
}
Automatically inline function;
no need to use inline keyword
before function header
Three Types of Functions
• Class member functions are classified into three categories:
• Constructors
• create objects (allocate memory, set initial state)
• Modifiers/set-methods
• change the state of objects
• Accessors/get-methods
• make information about the state of the object available outside the class
Constructor
• Goal:
• construct objects of the class
• allocate memory
• Constructors MUST have the same name as the class itself.
• They don't have a return type. It's simply omitted.
• Constructors can be overloaded, i.e., a class can have several constructors that have the same name but
different lists of parameters
• That's how you'll make instances of the class (objects).
• Example:
• Constructor of dateType class
• dateType();
• Constructor of rectangle class
• rectangle();
Constructor (Cont.)
• A default constructor: no parameters
• Initializer constructors: parameters specifying initial state of an object
• A copy constructor
• Called when an object is copied to another object of the same type
• Copy constructor is called when we:
• Initialize one object from another of the same type.
• Copy an object to pass it as an argument to a function.
• Copy an object to return it from a function.
• If no copy constructors is declared in the class, then an object is bitwise copied to another
object in the above 3 cases – which may be problematic especially if the objects contain
any pointer. That’s why it’s a good practice to put a copy constructor.
Constructor Example
class Rectangle{
public:
int width, length;
Rectangle(){width=length=0;} //default constructor
Rectangle(int w, int l){width=w; length=l;} //constructor with initializers
//copy constructor
Rectangle(const Rectangle &r){width=r.width; length=r.length;}
};
void print(Rectangle r){cout << r.width << ‘ ‘ << r.length << endl;}
Rectanlgle create(int w, int l){Rectangle r; r.width=w; r.length= l; return r;}
Rectangle r1; //default constructor is called
Rectangle r2(5,3.4); //initializer constructor is called
Rectangle r3= r2; //copy constructor is called: r3.Rectangle(r2);
print(r3); //copy constructor is called: Rectangle r = r3;//r.Rectangle(r3);
Rectangle t= create(4,2); //copy constructor is called: Rectangle t = r;
Destructor Function
• A destructor is a special member function that is called when the lifetime of an
object ends.
• The purpose of the destructor is to free the resources that the object may have
acquired during its lifetime.
• In a C++ class, destructor should be provided when memory is dynamically
allocated for some members of that class, because C++ doesn’t have an
automatic garbage collection mechanism (unlike Java)
• Destructor syntax:
~ class_name ();
Destructor Example
#include <iostream>
using namespace std;
ctor a1
ctor a2
struct A{
int *i; dtor a2
A (int k) {
i = new int; dtor a1
*i = k; Destructor Example Output
cout << “ctor ” << *i << '\n';
}
~A() {cout << “dtor ” << *i << '\n'; delete i;} //destructor
};
int main(){
A a1(1);//constructor is called to instantiate a1
if(1){ // nested scope
A a2(2); //constructor is called to instantiate a2
} // a2 out of scope; so destructor is called on a2
} // a1 out of scope; so destructor is called on a1
Class in a Separate Header File for Reusability
• For every data structure, we will create 3 files in
our Codeblocks project
• The declaration file (with .h extension)
• The definition file (with .cpp extension) • Header files
• The driver file (with .cpp extension) • Separate files in which class definitions are placed.
• Allow compiler to recognize the classes when used
elsewhere.
• Generally have .h filename extensions
• .cpp files for source-code implementations
• Class implementations
• Main programs
• Test programs
• Driver file
• A program used to test software (such as classes).
• Contains a main function so it can be executed
Basics
#ifndef DYNARR_H_INCLUDED
#define DYNARR_H_INCLUDED
class dynArr
{
private:
int *data;
int size;
public:
dynArr();
dynArr(int);
~dynArr();
void allocate(int);
void setValue(int, int);
int getValue(int);
};
#endif // DYNARR_H_INCLUDED
dynarr.h (header file)
Basics
#include "dynarr.h" void dynArr::allocate(int s)
#include <iostream> {
using namespace std; if(data!=NULL) delete [] data;
data = new int[s];
dynArr::dynArr() size = s;
{ }
data = NULL;
size = 0; int dynArr::getValue(int index)
} {
return data[index];
dynArr::dynArr(int s) }
{
data = new int[s]; void dynArr::setValue(int index, int
size = s; value)
} {
data[index] = value;
dynArr::~dynArr() }
{
if(data!=NULL)
delete [] data;
} dynarr.cpp (definition file)
Basics
#include "dynarr.h"
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
dynArr d(n);
int i;
for(i=0;i<n;i++)
d. setValue(i,3*i+1);
for(i=0;i<n;i++)
cout << d.getValue(i) << endl;
d.allocate(100);//reallocate space
for(i=0;i<n;i++)
cout << d.getValue(i) << endl; //prints garbage values
return 0;
}
main.cpp (driver file)
Template Class
• Now we have a neat class that gives us a 1D dynamic array (you are free to make
your own improvisations at home by adding more functions to the class)
• But it only works for integer type
• What if we are to make it versatile, so that it works for any type, e.g. float,
double and char
• Should we have separate classes for each type?
• Write the same code for each type with just minor changes?
• Instead, we can use template classes
Template Class
#ifndef DYNARR_H_INCLUDED
#define DYNARR_H_INCLUDED
template <class T>
class dynArr
{
private:
T *data;
int size;
public:
dynArr();
dynArr(int);
~dynArr();
void allocate(int);
void setValue(int, T);
T getValue(int);
};
#endif // DYNARR_H_INCLUDED
dynarr.h (declaration file)
Template Class
#include "dynarr.h" template <class T>
#include <iostream> void dynArr<T>::allocate(int s)
using namespace std; {
if(data!=NULL) delete [] data;
template <class T> data = new T[s];
dynArr<T>::dynArr() size = s;
{
}
data = NULL;
size = 0;
} template <class T>
T dynArr<T>::getValue(int index)
template <class T> {
dynArr<T>::dynArr(int s) return data[index];
{ }
data = new T[s];
size = s;
template <class T>
}
void dynArr<T>::setValue(int index, T
template <class T> value)
dynArr<T>::~dynArr() {
{ data[index] = value;
delete [] data; }
} dynarr.cpp (definition file)
Template Class
#include "dynarr.cpp"
#include <iostream>
using namespace std;
int main()
{
dynArr<int> di(10);
dynArr<double> dd(10);
int i;
for(i=0;i<10;i++)
{
di.setValue(i,3*i+1);
dd.setValue(i,7.29*i/1.45);
}
for(i=0;i<10;i++)
cout << di.getValue(i) << " " << dd.getValue(i) << endl;
return 0;
}
main.cpp (driver file)
A Complex Number Example
class Complex
{ Complex Complex::Add(Complex c)
public: {
Complex(); Complex t;
Complex(double, double); t.Real = Real + c.Real;
Complex Add(Complex); t.Imaginary = Imaginary + c.Imaginary;
void Print(); return t;
private: }
double Real, Imaginary; void Complex::Print()
}; {
cout << Real << endl;
Complex::Complex() cout << Imaginary << endl;
{ }
Real = 0;
Imaginary = 0;
} int main(void)
{
Complex::Complex(double r, double i) Complex A(1,1), B(2,3);
{ Complex C;
Real = r; C = A.Add(B);
Imaginary = i; C.Print();
} return 0;
}
Optional Part
Namespace (https://www.youtube.com/watch?v=ZZWTh142s4w)
#include <iostream> #include <iostream>
using namespace std; using namespace std;
namespace First { namespace First{
void sayHello() { void sayHello(){
cout << "First Namespace“ << endl; cout << "First Namespace" << endl;
} }
} }
namespace Second { namespace Second{
void sayHello() { void sayHello(){
cout << "Second Namespace“ << endl; cout << "Second Namespace" << endl;
} }
} }
int main() using namespace First;
{
First::sayHello(); int main () {
Second::sayHello(); sayHello();
return 0; return 0;
} }
Friend Function
class Complex
{
public:
Complex();
Complex(double, double);
void Print();
friend Complex AddComplex(Complex, Complex);
private:
double Real, Imaginary;
};
Complex::Complex() • The function has access to the private
{ members in the class declaration
Real = 0;
Imaginary = 0;
• The function is outside the scope of the class
}
Complex::Complex(double r, double i)
{
Real = r;
Imaginary = i;
}
Friend Function
void Complex::Print()
{
cout << Real << endl;
cout << Imaginary << endl;
}
Complex AddComplex(Complex a, Complex b)
{
Complex t;
t.Real = a.Real + b.Real;
t.Imaginary = a.Imaginary + b.Imaginary;
return t;
}
int main(void)
{
Complex A(1,1), B(2,3);
Complex C;
C = AddComplex(A, B);
C.Print();
return 0;
}
Operator Overloading
class Complex {
public:
Complex();
• We can use some operator symbols to
Complex(double, double); define special member functions of a class
Complex operator+(Complex);
Complex operator+(double); • Provides convenient notations for object
void Print(); behaviors
private:
double Real, Imaginary;
};
Complex::Complex()
{
Real = 0;
Imaginary = 0;
}
Complex::Complex(double r, double i)
{
Real = r;
Imaginary = i;
}
Operator Overloading
Complex Complex::operator+(Complex a){
Complex t;
t.Real = Real + a.Real;
t.Imaginary = Imaginary + a.Imaginary;
return t;
}
Complex Complex::operator+(double n){
Complex t;
t.Real = Real + n;
t.Imaginary = Imaginary + n;
return t;
}
void Complex::Print(){
cout << Real << endl;
cout << Imaginary << endl;
}
int main(void) {
Complex A(1,1), B(2,3), D(5,6), C;
C = A + B; //C = A.operator+(B);
C = C + 3.2; //C = C.operator+(3.2);
C.Print();
return 0;
}
Operator Overloading using friend function
With simple operator overloading we can’t do:
Complex A, C = 3.2+A;
To be able to write expressions like above, we need friend operator
function
Operator Overloading with friend function
class Complex {
double Real, Imaginary; //private, by default
public:
Complex();
Complex(double, double);
friend Complex operator+(double, Complex);
friend Complex operator+(Complex, double);
// Complex operator+(double n)
friend Complex operator++(Complex&);
void Print();
};
Complex::Complex()
{
Real = 0;
Imaginary = 0;
}
Complex::Complex(double r, double i)
{
Real = r;
Imaginary = i;
}
Operator Overloading with friend function
Complex operator+(double n, Complex a){
Complex t;
t.Real = n + a.Real;
void Complex::Print(){
t.Imaginary = n + a.Imaginary;
cout << Real << endl << Imaginary << endl;
return t;
}
}
int main(void) {
Complex operator+(Complex a, double n){
Complex A(1,1), B;
Complex t;
B = 3.2 + A;//operator+(3.2, A);
t.Real = n + a.Real;
A = A + 2.4;
t.Imaginary = n + a.Imaginary;
B=++A;//operator++(A);//a=A
return t;
A.Print();B.Print();
}
return 0;
Complex operator++(Complex &a) {
}
a.Real ++; a.Imaginary ++;
return a;
}
Overloading Relational Operator
class Complex {
public:
Complex();
Complex(double, double);
bool operator>(Complex);
void Print();
private:
double Real, Imaginary;
};
Complex::Complex() {
Real = 0;
Imaginary = 0;
}
Complex::Complex(double r, double i) {
Real = r;
Imaginary = i;
}
Overloading Relational Operator
bool Complex::operator>(Complex a){
if(Real > a.Real || (Real == a.Real && Imaginary > a.Imaginary))
return true;
else
return false;
}
void Complex::Print(){
cout << Real << endl;cout << Imaginary << endl;
}
int main(void) {
Complex A(1,1), B;
A.Print();
B.Print();
if(A>B) //A.operator>(B);
cout<<“A is greater”;
return 0;
}