ADTs in C++ In C++, member functions can be defined as part of a struct

Similar documents
Class Destructors constant member functions

Chapter 10 Introduction to Classes

CS201 - Introduction to Programming Glossary By

Short Notes of CS201

Fast Introduction to Object Oriented Programming and C++

Defining new types and interfaces

Lecture 18 Tao Wang 1

Roxana Dumitrescu. C++ in Financial Mathematics

Function Overloading

COMP 2355 Introduction to Systems Programming

Lecture 7. Log into Linux New documents posted to course webpage

CSCE 110 PROGRAMMING FUNDAMENTALS

2 ADT Programming User-defined abstract data types

Classes and Objects. Class scope: - private members are only accessible by the class methods.

Intermediate Programming, Spring 2017*

Distributed Real-Time Control Systems. Lecture 17 C++ Programming Intro to C++ Objects and Classes

C++ Programming. Classes, Constructors, Operator overloading (Continued) M1 Math Michail Lampis

Classes. Christian Schumacher, Info1 D-MAVT 2013

A brief introduction to C++

beginslide Chapter 6 The C++ Programming Language The Role of Classes

What will happen if we try to compile, link and run this program? Do you have any comments to the code?

EL2310 Scientific Programming

CS 376b Computer Vision

Programming in C and C++

Object-Oriented Programming

3.Constructors and Destructors. Develop cpp program to implement constructor and destructor.

CS

PIC 10A Objects/Classes

CS201- Introduction to Programming Current Quizzes

Object Oriented Design

Praktikum: Entwicklung interaktiver eingebetteter Systeme

Introduction Of Classes ( OOPS )

G52CPP C++ Programming Lecture 13

Introduction to C++ Systems Programming

Implementing Abstract Data Types (ADT) using Classes

CSE 303: Concepts and Tools for Software Development

GEA 2017, Week 4. February 21, 2017

04-19 Discussion Notes

C++ C and C++ C++ fundamental types. C++ enumeration. To quote Bjarne Stroustrup: 5. Overloading Namespaces Classes

Copying Data. Contents. Steven J. Zeil. November 13, Destructors 2

AN OVERVIEW OF C++ 1

Classes - 2. Data Processing Course, I. Hrivnacova, IPN Orsay

Classes: A Deeper Look

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #1 Examination 12:30 noon, Tuesday, February 14, 2012

Introduction to Classes

Constructor - example

Object Oriented Software Design II

Evolution of Programming Languages

Lecture 8: Object-Oriented Programming (OOP) EE3490E: Programming S1 2017/2018 Dr. Đào Trung Kiên Hanoi Univ. of Science and Technology

Structures and Member Functions

Introduction to Programming session 24

More About Classes. Gaddis Ch. 14, CS 2308 :: Fall 2015 Molly O'Neil

Where do we go from here?

EL2310 Scientific Programming

การทดลองท 8_2 Editor Buffer Array Implementation

Chapter 18 - C++ Operator Overloading

COMP6771 Advanced C++ Programming

l A class in C++ is similar to a structure. - It allows you to define a new (composite) data type. l A class contains the following: - variables AND

Midterm Review. PIC 10B Spring 2018

CE221 Programming in C++ Part 1 Introduction

Pointers. Developed By Ms. K.M.Sanghavi

Overloading Operators in C++

COMP6771 Advanced C++ Programming

CS 11 C++ track: lecture 1

B16 Object Oriented Programming

Cpt S 122 Data Structures. Introduction to C++ Part II

B16 Object Oriented Programming

! Data is stored in variables. - Perhaps using arrays and structs. ! Program is a collection of functions that perform

EL2310 Scientific Programming

Practice Problems CS2620 Advanced Programming, Spring 2003

CSE 374 Programming Concepts & Tools. Hal Perkins Fall 2015 Lecture 19 Introduction to C++

Distributed Real-Time Control Systems. Lecture 14 Intro to C++ Part III

A Tour of the C++ Programming Language

CPSC 427: Object-Oriented Programming

(5 2) Introduction to Classes in C++ Instructor - Andrew S. O Fallon CptS 122 (February 7, 2018) Washington State University

Outline. User-dened types Categories. Constructors. Constructors. 4. Classes. Concrete classes. Default constructor. Default constructor

Chapter 15 - C++ As A "Better C"

UEE1303(1070) S12: Object-Oriented Programming Constructors and Destructors

CS3157: Advanced Programming. Outline

Come and join us at WebLyceum

SFU CMPT Topic: Classes

OBJECT ORIENTED PROGRAMMING USING C++

Introducing C++ to Java Programmers

CS201 Some Important Definitions

! Data is stored in variables. - Perhaps using arrays and structs. ! Program is a collection of functions that perform

An Introduction to C++

Operator Overloading in C++ Systems Programming

Abstraction in Software Development

EECE.3220: Data Structures Spring 2017

the gamedesigninitiative at cornell university Lecture 7 C++ Overview

C++ Constructor Insanity

See the CS 2704 notes on C++ Class Basics for more details and examples. Data Structures & OO Development I

A Tour of the C++ Programming Language

C++ Addendum: Inheritance of Special Member Functions. Constructors Destructor Construction and Destruction Order Assignment Operator

CMSC 4023 Chapter 11

1. Describe History of C++? 2. What is Dev. C++? 3. Why Use Dev. C++ instead of C++ DOS IDE?

Software Engineering Concepts: Invariants Silently Written & Called Functions Simple Class Example

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

Abstract Data Types and Encapsulation Concepts

C++ Basics. Data Processing Course, I. Hrivnacova, IPN Orsay

Transcription:

In C++, member functions can be defined as part of a struct ADTs in C++ struct Complex { ; void Complex::init(double r, double i) { im = i; int main () { Complex c1, c2; c1.init(3.0, 2.0); c2.init(4.0, 0.0); c1.add(c2); 2 A member function has full access to the member variables of the object that invoked it, without qualification A member function can access the member variables of another object by passing it to the function in the normal way int main () { c1 re = 3.0 im = 2.0 c2 re = 4.0 im = 0.0 int main () { c1 re = 7.0 3.0 im = 2.0 c2 re = 4.0 im = 0.0 Complex c1, c2; c1.init(3.0, 2.0); c2.init(4.0, 0.0); c1.add(c2); Complex c1, c2; c1.init(3.0, 2.0); c2.init(4.0, 0.0); c1.add(c2); void Complex::init(double r, double i) { im = i; 3 4

Member functions can be implemented in one of two ways: Inside the class declaration In this case the function is automatically considered inline Outside the class declaration Struct definitions usually appear in a header file Inline functions are also implemented in the header file Ordinary (non-inline) functions are implemented in a source file There are various acceptable extensions:.cpp,.cc or.c struct Complex { void init(double r, double i) { im = i; ; #ifndef COMPLEX_H_ #define COMPLEX_H_ struct Complex { void init(double r, double i) { im = i; ; #endif complex.h #include "complex.h" complex.c 5 6 Unlike C, the struct definition appears in the header file To make sure the user accesses the struct only through the interface, we can control the user's access to specific parts of it Every member of the struct is either public or private Members that are private can only be accessed by functions belonging to the struct struct Complex { private: ; Complex c1, c2; c1.init(3.0, 2.0); c2.init(4.0, 0.0); c1.add(c2); double d = c1.re; We use the private section of the struct to encapsulate our data type as in our ADTs in C But if the struct is defined in the header file, doesn't this break encapsulation? No, encapsulation is not about hiding things from the user, it's about protecting the user from making mistakes However, unlike ADTs in C style, we do not have compile-time encapsulation Adding a field in a struct will require compilation of many files 7 8

The class keyword is nearly identical to the struct keyword The difference: the contents of a class are private by default The class keyword is usually used for implementing ADTs From now on, we will refer to our ADTs as classes struct Complex { private: equivalent Each member function must know which object invoked it The compiler implicitly sends a pointer named this to the member function, pointing to the calling object The this pointer is constant it cannot point to another target compilation void add(complex* const this, Complex c) { this-> this-> ; ; c1.add(c2); add(&c1, c2) 9 10 The this pointer can be used within the member function like a normal pointer However, in most cases it is not necessary to use it explicitly A common technique is to have a member function return the object it was invoked for This allows chaining several calls this-> this-> void Complex::init(double re, double im) { this->re = re; this->im = im; Complex c1, c2, c3; c1.add(c2).add(c3); To implement this, we need to return a reference to *this Complex& Complex::add(Complex c) { return *this; Complex Complex::add(Complex c) { return *this; 11 12

Some member functions do not modify their object Such member functions should work for const objects as well Declaring const in the end of a member function s prototype will enable it to work on a const object void init(double t, double i); double abs() const; ; void f(complex& c, const Complex& c2) { c.add(c2); c2.add(c); // error cout << c2.abs() << endl; double Complex::abs() const { return sqrt(re * re + im * im); compilation double abs(const Complex* const this) { return sqrt(re * re + im * im); In many cases we will encapsulate a field of a class using two member functions: A getter function for retrieving the value A setter function to allow updating the value Why not just make this variable public? Using a public field prevents us from changing the implementation without changing the interface For example: What if we decide to change Complex to use abs & arg? There are two common naming conventions for such functions: double Complex::getReal() const { return re; void Complex::setReal(double r) { double Complex::real() const { return re; void Complex::real(double r) { 13 14 A class may have static members and functions A static member is a variable that is part of the class, but does not belong to any specific object Only a single copy of this variable exists The variable exists throughout the life of the program, even if no object is ever created from this class A static member is effectively a global variable But it is part of the class namespace It can be designated as private main.cpp Complex c; c.init(complex::pi / 2.0, 0.0); complex.h static double pi; ; A static variable has to be defined in some source file to actually exist The class only declares the variable Static members are commonly used to define constants needed in the class If the constant is of an integral type (such as int), a definition is not needed complex.h static const double PI; ; complex.cpp const double Complex::PI = 3.14159265; 15 16

A static function is a function which is allowed to access the private parts of the class, but is not invoked by a particular object A static function can be called even if no object has been created A static function does not have access to a this pointer complex.cpp complex.h string Complex::ImaginaryUnit = "i"; static string ImaginaryUnit; void print(complex c) const; static const double PI; static void setimaginaryunit(string s); ; void Complex::print() { cout << re << "+" << im << imaginaryunit; void Complex::setImaginaryUnit(string s) { imaginaryunit = s; Complex c1; c1.init(2.0, 3.0); c1.print(); Complex::setImaginaryUnit("j"); c1.print(); main.cpp The use of functions such as init() is inelegant and error prone The programmer may forget to call it The programmer may call it twice Instead, a special member function called a constructor is used complex.h Complex(double r, double i); ; Complex one(1.0, 0.0); complex.cpp Complex::Complex(double r, double i) { im = i; 17 18 A constructor has no return value Several constructors can be overloaded with different parameters As with regular functions in C++ Default parameters are also allowed Complex(); Complex(double r, double i = 0); ; void print(const Complex& c) { // implementation Complex c1; // Complex::Complex() Complex c2(2.0, 1.0); // Complex::Complex(r,i) Complex c3(1.0); // Complex::Complex(r,0) Complex c4 = 3.0; // Complex::Complex(r,0) Complex* pc1 = new Complex; // Complex::Complex() Complex* pc2 = new Complex(); // Complex::Complex() Complex* pc3 = new Complex(-3.0, 1.0); // Complex::Complex(r,i) print(complex(0.0, 1.0)); // Complex::Complex(r,i); A constructor which receives no arguments is called a default constructor The default constructor is called when an object is created with no arguments The compiler will automatically generate a default constructor for any class that defines no constructors of its own The compiler-generated default constructor simply calls the default constructors of all the class members Every object is initialized by a constructor! there is an exception for "Plain old data" types, beyond the scope of this course * Complex c1; print(complex()); 19 20

When creating an array of objects, the default constructor is called for each of them Complex array1[10]; // Complex::Complex() [x10] Complex* parray = new Complex[10]; // Complex::Complex() [x10] Complex* parray2 = new Complex[10](); // Complex::Complex() [x10] If there is no default constructor available, a compilation error will occur. But how can this happen? If any non-default constructor is explicitly defined, the compiler no longer generates the default constructor automatically This can be solved by adding a default constructor explicitly Exception: Built-in types can be created without initialization This exists for backward-compatibility with C, and efficiency reasons int* parray = new int[10](); // initialize to zeros int* parray2 = new int[10]; // uninitialized In many cases, a constructor will allocate a resource E.g., allocate memory on the heap, open a file, open a network connection, In such a case, the resource must be freed when the object is destroyed Each class has a special member function called a destructor The destructor is automatically invoked when the object is destroyed class Array { int* data; int size; Array(int sz); ~Array(); int& atindex(int index); ; int main() { Array a(10); a.atindex(3) = 2; cout << a.atindex(7) << endl; Array::Array(int sz) { data = new int[sz]; size = sz; Array::~Array() { delete[] data; int& Array::atIndex(int index) { assert(index >= 0 && index < size); return data[index]; 21 22 Destructors take no arguments Therefore, there can be only one per class A destructor is called whenever an object is released, for example: When a local variable goes out of scope When a dynamically allocated object is explicitly deleted A temporary value is released at the "end of the line" void g(const Array& a); void f() { Array a(10); Array* ptr = new Array(20); Array* ptr2 = new Array(30); g(array(20)); // temporary Array is destructed "at the end of the line" delete ptr; // ptr->~array() is called // a.~array() is called // *ptr2 is leaked! There s a critical difference between initializing an object and assigning a value to it: Initialization occurs when a new object is created Assignment updates the values of an existing object Complex c(1.0, 1.0); Complex c2(c); Complex c3 = c; c = c2; 23 24

Lets look again at Array s constructor When are size and data initialized? When an object is created, first its members are initialized, and only then the constructor's body is executed By default, all members are initialized with their default constructors We can use different initialization with an initialization list Syntax for an explicit initialization list Array::Array(int n) { data = new int[n]; size = n; Array::Array(int n) : data(new int[n]), size(n) { // nothing left to do here, that's fine For a type T, the constructor T(const T&) is called the copy constructor This constructor initializes a new object by copying an existing object Array::Array(const Array& array) : data(new int[array.size]), size(array.size) { for (int i = 0; i < size; i++) { data[i] = array.data[i]; The copy constructor is extremely important as it is called whenever an object is passed or returned from a function by value int main() { Array a(10) f(a); g(a); Array b = h(); void f(array a) {... void g(array& a) {... Array h() { return Array(10); 25 26 The compiler will automatically generate a copy constructor for any class that does not define one explicitly Even if other constructors have been defined The compiler-generated copy constructor simply calls the copy constructors of all the class members If the class uses pointers or allocates resources (such as dynamic memory), a user-defined copy constructor is probably needed When an object is created, its constructor first calls the constructors of all the class members, and only then executes the constructor's body Members are constructed in the order they are defined in the class When an object is destroyed, it s destructor first executes the destructor's body, and then calls the destructors of all of the members Members are destructed in reverse order of creation A compiler-generated copy c'tor for Array will look like this: Array::Array(const Array& array) : data(array.data), size(array.size) { class A { //... A(); ~A(); ; class B { A a1, a2; B() {... ~B() {... ; 27 28

We will recreate our set of integers ADT as a class in C++ setcreate, setcopy and setdestroy will be replaced by constructors and destructors We will skip iterators and the filter function for now To get these right in C++ we need operator overloading and templates 1 Array 8 3?? 1, 8, 3 Equal sets 8, 1, 3 #ifndef SET_H_ #define SET_H_ #include <string> class Set { Set(); Set(const Set& set); ~Set(); bool add(int number); bool remove(int number); bool contains(int number) const; int getsize() const; Set unionwith(const Set&) const; Set intersectwith(const Set&) const; set.h (1/2) set.h (2/2) private: int* data; int size; int maxsize; int find(int number) const; void expand(); static const int EXPAND_RATE = 2; static const int INITIAL_SIZE = 10; static const int NUMBER_NOT_FOUND = -1; ; #endif /* SET_H_ */ size maxsize std::string tostring() const; 29 30 #include "set.h" #include <iostream> using std::cout; using std::endl; int main() { Set set1; Set set2; for (int j = 0; j < 20; j += 2) { set1.add(j); #include "set.h" #include <algorithm> #include <sstream> using std::swap; using std::ostringstream; for (int j = 0; j < 12; j += 3) { set2.add(j); Set unionset = set1.unionwith(set2); Set intersectionset = set2.intersectwith(set2); cout << set1.tostring() << endl; cout << set2.tostring() << endl; cout << unionset.tostring() << endl; cout << intersectionset.tostring() << endl; Set::Set() : data(new int[initial_size]), size(0), maxsize(initial_size) { 31 32

Set::Set(const Set& set) : data(new int[set.getsize()]), size(set.getsize()), maxsize(set.getsize()) { for(int i = 0; i < size; i++) { data[i] = set.data[i]; Set::~Set() { int Set::find(int number) const { for(int i = 0; i < size; i++) { if (data[i] == number) { return i; return NUMBER_NOT_FOUND; bool Set::contains(int number) const { return find(number)!= NUMBER_NOT_FOUND; delete[] data; int Set::getSize() const { return size; 33 34 void Set::expand() { int newsize = maxsize * EXPAND_RATE; int* newdata = new int[newsize]; for (int i = 0; i < size; ++i) { bool Set::add(int number) { if (contains(number)) { return false; if (size >= maxsize) { expand(); newdata[i] = data[i]; delete[] data; data[size++] = number; return true; data = newdata; maxsize = newsize; bool Set::remove(int number) { int index = find(number); if (index == NUMBER_NOT_FOUND) { return false; data[index] = data[--size]; return true; 35 36

37 Set Set::unionWith(const Set& set) const { Set result = set; for (int i = 0; i < size; ++i) { result.add(data[i]); return result; Set Set::intersectWith(const Set& set) const { Set result; for (int i = 0; i < size; ++i) { if (set.contains(data[i])) { result.add(data[i]); return result; we will see in the next lecture a more * common way of enabling printing of a class 38 std::string Set::toString() const { ostringstream os; os << "{"; for(int i = 0; i < size; i++) { if (i > 0 ) { os << ","; os << " " << data[i]; os << " "; return os.str(); There is a difference between copying and assignment int main() { Set set1; Set set2; for (int j = 0; j < 20; j += 2) { set1.add(j); set2 = set1; To solve this problem we need to overload operator= Overloading operators is discussed next Within C++, there is a much smaller and cleaner language struggling to get out. - Bjarne Stroustrup 39 40