COSC 2P95 Lab 5 Object Orientation

Similar documents

Short Notes of CS201

CS201 - Introduction to Programming Glossary By

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

C:\Temp\Templates. Download This PDF From The Web Site

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

The issues. Programming in C++ Common storage modes. Static storage in C++ Session 8 Memory Management

static CS106L Spring 2009 Handout #21 May 12, 2009 Introduction

MITOCW ocw f99-lec07_300k

Supporting Class / C++ Lecture Notes

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

COP Programming Assignment #7

CSE 303: Concepts and Tools for Software Development

Formal Methods of Software Design, Eric Hehner, segment 24 page 1 out of 5

Stream States. Formatted I/O

Chapter 10 :: Data Abstraction and Object Orientation

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #2 Examination 12:30 noon, Thursday, March 15, 2012

Lecturer: William W.Y. Hsu. Programming Languages

Financial computing with C++

Assignment 1: grid. Due November 20, 11:59 PM Introduction

CS93SI Handout 04 Spring 2006 Apr Review Answers

Chapter 17 vector and Free Store

The vector Class and Memory Management Chapter 17. Bjarne Stroustrup Lawrence "Pete" Petersen Walter Daugherity Fall 2007

PIC10B/1 Winter 2014 Exam I Study Guide


Object-Oriented Principles and Practice / C++

CSE 333 Midterm Exam July 24, Name UW ID#

The Stack, Free Store, and Global Namespace

Instantiation of Template class

A brief introduction to C++

CPSC 427: Object-Oriented Programming

CS201 Some Important Definitions

Programs in memory. The layout of memory is roughly:

Formal Methods of Software Design, Eric Hehner, segment 1 page 1 out of 5

Chapter 9 :: Data Abstraction and Object Orientation

Operator overloading

Assignment of Structs

Linked Lists. What is a Linked List?

2 ADT Programming User-defined abstract data types

Chapter 17 vector and Free Store. Bjarne Stroustrup

CISC 2200 Data Structure Fall, C++ Review:3/3. 1 From last lecture:

Object-Oriented Principles and Practice / C++

CS 11 C++ track: lecture 1

CS Final Exam Review Suggestions - Spring 2014

CS193D Handout 10 Winter 2005/2006 January 23, 2006 Pimp Your Classes

Classes in C++98 and C++11

Chapter 13: Copy Control. Overview. Overview. Overview

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

CS107 Handout 08 Spring 2007 April 9, 2007 The Ins and Outs of C Arrays

CS201- Introduction to Programming Current Quizzes

CS 11 C track: lecture 5

And Even More and More C++ Fundamentals of Computer Science

Lecture Topics. Administrivia

Chapter 1 Getting Started

COP4530 Data Structures, Algorithms and Generic Programming Recitation 4 Date: September 14/18-, 2008

Interview Questions of C++

COSC 2P95. Procedural Abstraction. Week 3. Brock University. Brock University (Week 3) Procedural Abstraction 1 / 26

Suppose we find the following function in a file: int Abc::xyz(int z) { return 2 * z + 1; }

III. Classes (Chap. 3)

1 Shyam sir JAVA Notes

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

Programming Abstractions

University of Maryland Baltimore County. CMSC 202 Computer Science II. Fall Mid-Term Exam. Sections

Object-Oriented Principles and Practice / C++

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

PIC 10B Lecture 1 Winter 2014 Homework Assignment #3

Post Experiment Interview Questions

Chapter 17 vector and Free Store

Part I: Short Answer (12 questions, 65 points total)

CSc 328, Spring 2004 Final Examination May 12, 2004

Object Oriented Software Design II

CS250 Final Review Questions

Abstract Data Types (ADT) and C++ Classes

A506 / C201 Computer Programming II Placement Exam Sample Questions. For each of the following, choose the most appropriate answer (2pts each).

The Design Process. General Development Issues. C/C++ and OO Rules of Thumb. Home

CSE 333 Midterm Exam Nov. 3, 2017 Sample Solution

CSC1322 Object-Oriented Programming Concepts

// Initially NULL, points to the dynamically allocated array of bytes. uint8_t *data;

INITIALISING POINTER VARIABLES; DYNAMIC VARIABLES; OPERATIONS ON POINTERS

Dynamic Allocation in C

CSE 143. Linked Lists. Linked Lists. Manipulating Nodes (1) Creating Nodes. Manipulating Nodes (3) Manipulating Nodes (2) CSE 143 1

Concepts (this lecture) CSC 143. Classes with Dynamically Allocated Data. List of ints w/dups (cont.) Example: List of ints with dups.

PROFESSOR: Last time, we took a look at an explicit control evaluator for Lisp, and that bridged the gap between

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

Abstract Data Types (ADTs) 1. Legal Values. Client Code for Rational ADT. ADT Design. CS 247: Software Engineering Principles

Week 8: Operator overloading

Pointers. Developed By Ms. K.M.Sanghavi

MITOCW ocw apr k

CS250 Final Review Questions

CS304 Object Oriented Programming Final Term

Homework 4. Any questions?

EINDHOVEN UNIVERSITY OF TECHNOLOGY Department of Mathematics and Computer Science

An Introduction to C++

Slide 1 CS 170 Java Programming 1

Object Reference and Memory Allocation. Questions:

EECE.3220: Data Structures Spring 2017

BEGINNER PHP Table of Contents

QUIZ. What is wrong with this code that uses default arguments?

CS 247: Software Engineering Principles. ADT Design

Abstract. Vector. Overview. Building from the ground up. Building from the ground up 1/8/10. Chapter 17 vector and Free Store

Transcription:

COSC 2P95 Lab 5 Object Orientation For this lab, we'll be looking at Object Orientation in C++. This is just a cursory introduction; it's assumed that you both understand the lecture examples, and will be using the reference of your preference to find additional information. Step One: Declaring Classes We're going to start simple: a basic template for a trivial record with public accessors and updaters. These member functions will operate on the two member variables. class Record { private: long rid; //Record ID char *content; public: long getrid() { return rid; char *getcontent() { return content; void setrid(long rid) { this->rid=rid; ; void setcontent(char cstring) { //How would we do this? Do we allocate? Beware memory leaks! Note the this pointer. This is an implicit pointer provided to methods (i.e. those member functions performed by the object). Step Two: Constructors Of course, what we're missing is a way to easily initialize the object. The updaters aren't really an ideal substitute. For this example, we'll actually phase out those updaters. Let's start with a single constructor: we have two member variables (instance variables), so we'll take two parameters. Record(long rid, char content[]) { this->rid=rid; while (content[clength]!='\0') clength++; for (int i=0;i<clength;i++) this->content[i]=content[i]; Using this record class is pretty easy. e.g. Record r(23l, contented ); char c[80]; cin>>c; Record s(45l,c);

Well, that's not bad, but we have a problem: we're dynamically allocating memory on the heap, but what happens when we no longer need the record? The pointer can be easily reclaimed, but not the memory it's pointing to. Though we could hypothetically add a method to release the memory when manually invoked, that's not a reliable approach. Instead, we want to guarantee that some code will run when the object is deallocated. i.e. we need a destructor. Step Three: Destructor Simply add the following: ~Record() { delete[] content; (okay, so maybe this didn't need to be its own step) So now we're done, right? yeah sure Query: remembering that classes are based on structs, what happens if we pass a Record to a procedure to modify? Will it change the original or not? Step Four: Copy Constructor Temporarily make the following changes: Comment out your destructor Make the instance variables public Add the following procedure to the file (i.e. not to the class) void mutate(record r) { r.rid=77; r.content[0]='z'; Suppose you invoked it with: Record r(23,"howdy there!"); cout<<r.rid<<":"<<r.content<<endl; mutate(r); cout<<r.rid<<":"<<r.content<<endl; Before you actually run it, what would you expect? Now try running it. Ouch! What happened? It's true. Just like structs, when you use an object as an argument to a procedure, it wants to create a copy. It passes by value. However, one of these values is the pointer content, which contains a fixed place in memory. Basically, if the original record contained an rid of 23 and a content address of 0xFF08, then the new (copy) record will have a different long that happens to contain 23, and a different content address that happens to hold the value 0xFF08. So, why did we comment out the destructor? Because, if it isn't commented, then when we leave the procedure it automatically deallocates the parameter, which includes a deallocation of 'content' from the heap. Once the program ends, it also tries to deallocate, including deleting the 'content' (which has already been deleted).

The solution? Overload the copy constructor, so that we can make the pointer contain a different memory address. Add the following: Record(const Record &original):rid(original.rid) { while (original.content[clength]!='\0') clength++; clength++; for (int i=0;i<clength;i++) this->content[i]=original.content[i]; Also, uncomment the destructor, and change the instance variables to being private again. Step Five: Stream Insertion (Output) When it comes to output, we could simply use the accessors to get the two member variables, and we could even write a simple procedure to accept a reference to the record and print out the record. What's more, if we also had another parameter for the specific ostream, then we could use it for both terminal and file output. But what operation would that actually rely on? The stream insertion ( << ). Why can't we just define a stream insertion operator for our record? Naturally, we can. Overloading operators is relatively simple. The biggest catch is that operators defined as member functions must use that object as the left-hand side operand. But stream insertion uses the ostream as the left-hand side. As such, it can't be a normal member function (i.e. it can't be a proper method). However, if we write a separate function, it will still need access to the inner contents of the record. To achieve all of this, we simply use a friend function. First, to the class, let's add a friend declaration: friend std::ostream& operator<<(std::ostream &out, Record &rec); Make sure to put it under the public area of the class. Now, somewhere else within the class, let's add the implementation: std::ostream& operator<<(std::ostream &out, Record &rec) { std::out<<'['<<rec.rid<<':'<<rec.content<<']'; Note: if you prefer, you can combine the two, and add the following to the class: friend std::ostream& operator<<(std::ostream &out, Record &rec) { std::out<<'['<<rec.rid<<':'<<rec.content<<']'; However, even if you do that, as a friend function, it won't really be a method (that is, it isn't performed by the object, and don't rely on the this pointer). If you want to overload the stream extraction ( >> ) as well, you certainly can, but automated reading from a stream is often less essential than a simple method of output. Naturally, there are quite a few other operators we could also overload (some as friend functions; some as member functions), but very few would really make sense for this sort of record.

You're still encouraged to take a look at them sometime (the parenthesis operator is especially interesting). For now, let's look at that record ID Step Six: Static Functions and Variables The current version is fine, but there's a usage issue: ID values like that are typically autoincrementing. What we'd prefer would be to not need to specify the ID at all, and somehow automagically having sequentially-incrementing IDs assigned to each new Record. Actually, we can do that (pretty easily)! First, add this to the class: static long ridcount; //Tied to the class; not the object Because it's static, it's tied to the class; not any object. However, we can't initialize it here. So add this after the class: long Record::ridCount=0; Next, add the following to the class (probably under private): static long nextridcount() { return ridcount++; So, how does this help us? Remove the RID parameter from the constructor (leaving it with only content). Next, change this->rid=rid; to this->rid=nextridcount(); Step Seven: Assignment Operator Try the following somewhere: Record r("abba"),s("betta"); r=s; It crashes. Why? It's because that doesn't use the copy constructor; it uses assignment operator. Why should that matter? Two problems: 1. Just as with the original copy constructor, we now end up trying to deallocate the same array twice 2. Before the current array is clobbered, we don't deallocate its memory at all There are three solutions: 1. Properly implement an overloaded assignment operator: Make sure to check if it's being assigned to itself! (Basically, check if this matches the address of the received parameter) If it is, simply return *this Deallocate the old memory, then allocate new memory to hold the contents of the parameter Copy over the contents 2. Use the older C++ approach of overloading the assignment operator, but don't give it any actual content, and simply put it under private e.g. Record& operator=(const Record &other) { 3. Use the C++11 (and above) approach of deleting the assignment operator e.g. Record& operator=(const Record &other) = delete; Pick any of the three. I'll be assuming #2 from this point onward.

Step Eight: Organization You now have a functioning class. However, it's cluttering up the main source file. Ideally, we'd like to be able to separate it out. Create two new files: Record.cpp and Record.h. At the beginning of your main source file, add #include "Record.h" Next, we wish to move all of our class into those two files. For Record.h: #include <iostream> class Record { private: long rid; //Record ID char *content; static long ridcount; //Tied to the class; not the object static long nextridcount(); Record& operator=(const Record &other) { public: Record(char content[]); Record(const Record &original); ~Record(); long getrid(); char *getcontent(); friend std::ostream& operator<<(std::ostream &out, Record &rec); ; For Record.cpp: #include "Record.h" long Record::nextRIDCount() { return ridcount++; long Record::ridCount=0; Record::Record(char content[]) { this->rid=nextridcount(); while (content[clength]!='\0') clength++; clength++; for (int i=0;i<clength;i++) this->content[i]=content[i]; Record::Record(const Record &original):rid(original.rid) { while (original.content[clength]!='\0') clength++; clength++; for (int i=0;i<clength;i++) this->content[i]=original.content[i]; Record::~Record() { delete[] content; long Record::getRID() { return rid;

char *Record::getContent() { return content; std::ostream& operator<<(std::ostream &out, Record &rec) { std::out<<'['<<rec.rid<<':'<<rec.content<<']'; As mentioned above, in your main source file, remember to #include "Record.h". Since we're defining the method bodies in a separate file, notice that the headers are slightly different in Record.cpp. Specifically, the methods have Record:: prepended to them. Note that your g++ line has changed a little. Assuming a main source file of inagaddadavida.cpp: g++ -o inagaddadavida inagaddadavida.cpp Record.cpp (As mentioned in lecture, there's no need to include Record.h, as that's what the #include lines are for) Submission Task Write a very simple program to demonstrate that you can make use of a couple of Records. All you need do is output a couple different records, with auto-incrementing record IDs. Submission To demonstrate that you understand the content from this lab, simply show the output of your program for the submission task to your lab demonstrator.