EE3491/EE3490E –
Kỹ thuật lập trình /
Programming Techniques
Chapter 7: Class and
Objects – Part 2
Lecturer: Dr. Hoang Duc Chinh (Hoàng Đức Chính)
Department of Industrial Automation
School of Electrical Engineering
Email:
[email protected] © HĐC 2022.1
Content
7.1. Create and destroy an object
7.2. Constructor and destructor
7.3. Operator overloading
7.4. Friend declaration
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 2
7.1. Create and destroy an object
How many ways to create/destroy an object?
Automatically create and destroy: define a variable belonging to a class
Memory space of the object (consisting of member variables) is allocated as
normal variables
Memory space of the object is freed once it exists the scope of definition
class X {
int a, b;
...
};
void f( X x1) {
if (..) {
The object is created in stack
X x2;
... The memory allocated to x2 is freed here
}
} The memory allocated to x1 is freed here
X x; The object is created in data segment
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 3
7.1. Create and destroy an object
Create/destroy an object automatically by using new and
delete
X* pX = 0;
void f(...) {
if (..) {
pX = new X; The object is created in free-store
...
}
}
void g(...) {
...
if (pX != 0) {
Memory space of the object
delete pX;
... in heap is freed
}
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 4
Problem 1: Object initialization
Once it is created, the status of the object includes inner data and
relationships is undefined it is unsafe, less reliable and
inconvenient to use
X x; // x.a= ?, x.b= ?
X *px= new X; // px->a = ?, px->b = ?;
class Vector { int n; double *data; ... };
Vector v; // v.n= ?, v.data= ?
How to initialize an object with its status as desired right after it
is created?
X x = {1, 2};// Error! cannot access private members
How to create an object which is a copy of another object with
different type?
class Y { intc, d; };
Y y = x; // Error, X and Y are not the same type,
// they are not compatible
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 5
Problem 2: Resource management
How to perform dynamic memory allocation and deallocation safely?
class Vector {
intnelem;
double *data;
public:
void create(int n) { data = new double[nelem=n];}
void destroy() { delete[] data; nlem= 0; }
void putElem(inti, double d) { data[i] = d; }
};
Vector v1, v2;
v1.create(5);
// forget to call create for v2
v2.putElem(1,2.5);// BIG problem!
// forget to call destroy for v1, also a BIG problem
Similar issues when working with files, communication ports and other
resources in the computer
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 6
Common solution: Constructor and
destructor
A constructor is always called whenever an object is created, so
is the destructor when the object is destroyed
class X { int a, b;
public:
X() { a = b = 0; } // constructor (1)
X(int s, int t) { a = s; b = t;} // constructor (2)
~X() {} // destructor
};
Call constructor (1) without arguments
void f(X x1) {
(the default constructor)
if (..) {
X x2(1,2); Call constructor (2)
Call
X x3(x2);
destructor
...
of x1 Call copy constructor
} Call destructor
} of x2, x3
X *px1 = new X(1,2), *px2 = new X;
delete px1; delete px2;
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 7
7.2. Writing constructor and
destructor
Constructor is used to initialize and allocate memory resource
Destructor is used to free allocated memory resource
A class can have a few constructors (different in number of arguments or data
type of the arguments)
By default, compiler generates a non-argument constructor and a copy
constructor
Usually, implementation code of the default constructor generated by the compiler is
empty
Usually, implementation code of the default copy constructor generated by the compiler
copies the object data bit by bit
When developing a class, it is possible to rewrite the default constructor, copy constructor
and other constructors as desired
Each class has only one destructor, if the destructor is not defined, the
compiler will generate one
Usually, implementation code of the default constructor generated by the compiler is
empty
If required, it is possible to rewrite the destructor implementation as desired
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 8
Example: improved Time class
class Time {
int hour, min, sec;
public:
Time() : hour(0), min(0), sec(0) {}
Time(int h, int m=0, int s=0) { setTime(h,m,s); }
Time(const Time& t):
hour(t.hour),min(t.min),sec(t.sec) {}
...
};
void main() {
Time t1; // 0, 0, 0 It is unnecessary to define
Time t2(1,1,1); // 1, 1, 1 the copy constructor and
Time t3(1,1); // 1, 1, 0
the destructor for this class!
Time t4(1); // 1, 0, 0
Time t5(t1); // 0, 0, 0
Time t6=t2; // 1, 1, 1
Time* pt1= new Time(1,1); // 1, 1, 0
...
delete pt1;
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 9
Example: improved Vector class
User requirements:
Simple declaration as basic data types
Safe to use, users do not have to call functions to allocate and deallocate
memory
Example of usages:
Vector v1; // v1 has 0 elements
Vector v2(5,0); // v2 has 5 elements init. with 0
Vector v3=v2; // v3 is a copy of v2
Vector v4(v3); // the same as above
Vector f(Vectorb) {
double a[] = {1, 2, 3, 4};
Vector v(4, a);
...
return v;
}
// Do not care about memory management
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 10
Version 1
class Vector {
int nelem;
double* data;
public:
Vector() : nelem(0), data(0) {}
Vector(int n, double d =0.0); const member functions
Vector(int n, double *array); disable the permission for
Vector(const Vector&); changing member variables
~Vector();
int size() const { return nelem; }
double getElem(int i) const { return data[i];}
void putElem(int i, double d) { data[i] = d; }
private:
void create(int n) { data = new double[nelem=n]; }
void destroy(){ if (data != 0) delete [] data; }
};
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 11
Constructor and destructor
Constructor is used to initialize and allocate memory
resource
Destructor is used to free allocated memory resource
Vector::Vector(int n, double d) {
create(n);
while (n--> 0)
data[n] = d;
}
Vector::Vector(int n, double* p) {
create(n);
while (n--> 0)
data[n] = p[n];
}
Vector::~Vector() {
destroy();
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 12
Special case: copy constructor
copy constructor is called when copying an object
Declaring x2-x4 as below:
X x1;
X x2(x1);
X x3 = x1;
X x4 = X(x1);
When passing argument with a value to a function or when a
function return an object
void f(X x) { ... }
X g(..) {
X x1;
f(x1);
...
return x1;
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 13
Syntax of the copy constructor
class X {
int a, b;
public: (1) Pass argument with
value and copy
X() : a(0), b(0) {}
X(X x); // (1) (2) As (1)
X(const X x); // (2)
? (3) Not copy the argument,
X(X& x); // (3)
however x can be changed
X(const X& x); // (4)
unintendedly inside the
... function
};
void main() { (4) Not copy the argument,
safe for the origin
X x1;
correct syntax!
X x2(x1);
...
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 14
When to define the copy constructor?
When the default copy constructor cannot satisfy the requirements
E.g.: if the copy constructor is not defined, code generated by the
compiler automatically is as below:
Vector::Vector(const Vector& b)
: nelem(b.nelem), data(b.data) {}
Problem: simply copy pointers, two objects use the same memory
space allocated for their elements
a.nelem:5 b.nelem:5
Vector a(5);Vector b(a);
a.data b.data
0 0 0 0 0
In this case
Vector::Vector(constVector& a) {
create(a.nelem);
for (inti=0; i < nelem; ++i)
data[i] = a.data[i];
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 15
Attentions
A few constructors but only one destructor destructor must be
consistent with all the constructors
E.g. in Vector class, there is a constructor allocating memory, but not the
default constructor destructor needs to deal with all the cases
When the constructor allocates and occupies resources, it is
required to redefine destructor
In a class, there is destructor definition, it is almost certain to
define the copy constructor if it is allowed
Object copy can be prohibited by defining the copy constructor
in private, e.g.:
class Y { int a, b; Y(const&);
... };
void main() { Y y1;
Y y2=y1;// error!
... }
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 16
7.3. Operator overloading
One of the most well-known technique in C++
It enables to apply arithmetic operators for complex numbers or
vector such as +, -, *, / in the same way as for real numbers. E.g.:
class Complex {
double re, im;
public:
Complex(double r = 0, double i =0): re(r), im(i) {}
...
};
Complex z1(1,1), z2(2,2);
Complex z = z1 + z2;// ???
What’s the basic? The last line can be written as:
Complex z = z1.operator+(z2); Operator function can be
or implemented as a member function
Complex z = operator+(z1,z2); or a non-member function
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 17
Example: arithmetic operators for
complex number
class Complex {
double re, im;
public:
Complex(double r = 0, double i =0): re(r),im(i) {}
double real() const { return re; }
double imag() const { return im; }
Complex operator+(const Complex& b) const {
Complex z(re+b.re, im+b.im);
return z;
}
Complex operator-(const Complex& b) const {
return Complex(re-b.re, im-b.im);
}
Complex operator*(const Complex&) const;
Complex operator/(const Complex&) const;
Complex& operator +=(const Complex&);
Complex& operator -=(const Complex&);
...
};
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 18
Example: arithmetic operators for
complex number
#include “mycomplex.h”
Complex Complex::operator*(const Complex& b) const {
...// left for exercise!
}
Complex Complex::operator/(const Complex& b) const {
...// left for exercise!}
Complex&Complex::operator+=(const Complex& b) {
re += b.re; im+= b.im;
return *this;
}
Complex& operator -=(const Complex&) { ... }
bool operator==(const Complex& a, const Complex& b) {
return a.real() == b.real() && a.imag() == b.imag();
}
void main() {
Complex a(1,1), b(1,2);
Complex c = a+b;
a = c += b;// a.operator=(c.operator+=(b));
if (c == a) { ... }
} return?
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 19
Which operators can be overloaded?
Most of the operators in C++, e.g.:
Arithmetic operators ++ -- + - * / % += -= ...
Logical operators && || ! & &= | |= ...
Relational operators == != > < >= <=
Bitwise operators << >> >>= <<=
Other operators [] () -> * , ...
Only 4 operators cannot be applied
Scope resolution operator ::
Class member access operator .
Pointer to member of pointer ->*
Conditional operator ?:
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 20
7.4 Friend declaration
Problems: some non-member functions implemented externally, or
member functions of another class cannot access directly to an object’s
member less efficient
Solution: Enable the class to declare a “friend”, it can be a non-member
function, a member function of another class, or even another class
Example:
class Complex { ...
friend bool operator==(const Complex&,const Complex&);
friend class ComplexVector;
friend ComplexVectorMatrix::eigenvalues();
...
}
bool operator==(const Complex& a, const Complex& b) {
return a.re== b.re&& a.im== b.im;
}
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 21
Homework
Based on Vector structure and related functions
implemented in Chapter 4, build Vector class with necessary
member functions
Declare a class in order to store student information, it
should include the following attributes:
Student number (identity): Integer
Full name: String
Year of birth: Integer
Declare and define the class to manage students by member
functions which perform:
Input student full name
Input student number
Input year of birth
Search and display student information with given student number
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 22
END OF CHAPTER 7
Chapter 7: Class and Objects - Part 2 © DIA 2022.1 23