0% found this document useful (0 votes)
57 views55 pages

Session 6 - Class Basics Contd : Deep Copies Custom Iostream Operators Conversion Operators

This document discusses various class basics topics including: 1) Event loops that check for user input like keyboard presses and mouse clicks. 2) The main function and command line arguments. 3) Detecting keyboard events by checking if a key is pressed. 4) The difference between shallow and deep copies and how to implement deep copies using copy constructors and assignment operators. 5) Custom I/O stream operators by overloading the insertion and extraction operators. 6) Returning references from functions to avoid unnecessary copying. 7) The issues of dangling references and variable scope. 8) Input overflow from reading strings larger than the buffer size.

Uploaded by

Nguyen Phu Tai
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
57 views55 pages

Session 6 - Class Basics Contd : Deep Copies Custom Iostream Operators Conversion Operators

This document discusses various class basics topics including: 1) Event loops that check for user input like keyboard presses and mouse clicks. 2) The main function and command line arguments. 3) Detecting keyboard events by checking if a key is pressed. 4) The difference between shallow and deep copies and how to implement deep copies using copy constructors and assignment operators. 5) Custom I/O stream operators by overloading the insertion and extraction operators. 6) Returning references from functions to avoid unnecessary copying. 7) The issues of dangling references and variable scope. 8) Input overflow from reading strings larger than the buffer size.

Uploaded by

Nguyen Phu Tai
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 55

SESSION 6 – CLASS BASICS

CONTD…
DEEP COPIES
CUSTOM IOSTREAM OPERATORS
CONVERSION OPERATORS
Event Loops - ( WS5 )
WinMain(){
while(!done){
if(‘R’)… // user pressed ‘R’
if(‘S’)… // user pressed ‘S’
if(‘L’)…
… [other keys]
… [other mouse clicks]

if(‘Clicked close’){
done = true;
}
}
Command line main()function

int main(){

step1();
step2();
step3();
cout << “done”;

return 0;
}
Detecting Keyboard Events ( WS5 )

bool sp; // S Pressed?


if (keys['S'] && !sp) {


sp = TRUE; // pressing the S key
… [game code goes here]
}
if (!keys['S']){
sp = FALSE; // not pressing the S key
}
Releas
Press ●
‘S’ && !sp Hold ●
‘S’ && sp
e

!‘S’ && !sp
Detecting Keyboard Events ( WS5 )

bool sp; // S Pressed?


if (keys['S'] && !sp) {


sp = TRUE; // pressing the S key
… [game code goes here]
}
if (!keys['S']){
sp = FALSE; // not pressing the S key
}
Order Order
ISBN* nbr; = ISBN* nbr;
(shallow copy)

ISBN
Shallow copies copy the ADDRESS of pointers
but they don’t copy the object they point TO.
(deep copy) Order
Order
ISBN* nbr; = ISBN* nbr;

ISBN = ISBN
Deep copies make copies of each data object
instead of just copying pointers to data objects.
If you want to do deep copies, you need to write
a copy constructor.

Order::Order(Order& source) {
// new ISBN object
this->isbn = ISBN(source.isbn);
ordered = source.ordered;
this->delivered = source.delivered;
// You don’t have to say “this”
}
If you want to do deep copies, you need to write a
copy constructor and an assignment operator.

Order::Order(Order& source) {
// new ISBN object
this->isbn = ISBN(source.isbn);
ordered = source.ordered;
this->delivered = source.delivered;
// You don’t have to say “this”
}
If you want to do deep copies, you need to write a
copy constructor and an assignment operator.

Order::operator= (Order& rhs) {


// new ISBN object
this->isbn = ISBN(rhs.isbn);
this->ordered = rhs.ordered;
this->delivered = rhs.delivered;
}
If you want to do shallow copies, you
don’t need a copy constructor.

Order Order
ISBN* nbr; = ISBN* nbr;
(shallow copy)

ISBN
Resources

• Resources are stored outside the memory


allocated to an object. 
• Instance variables that refer to resources
(resource instance variables) include pointers
to
 dynamic arrays in freestore memory, and
 file structures
Resource instance variables example

a pointer !
Copying
• If we were to make a shallow copy of a Student
object, the original and the copy would point to the
same resource: grade pointer
• If any changes the grades in the copy, the original
referred to the changed grades and no longer to the
original grades.

This behavior is not what we normally expect


from a copy.
Copying…
• For each resource variable, we obtain a pointer to a
new resource and copy the original into that
resource. 
• To enable deep copying, we overwrite the compiler
defaults for two member functions:
 the copy constructor and
 the assignment operator

If we do not define a copy constructor, the compiler


inserts one that makes a shallow copy.  If we do not
define an assignment operator, the compiler inserts
one that performs a shallow assignment. 
Copy Constructor

• The copy constructor copies information from


an existing object to a newly created object.
• The compiler calls this constructor whenever
an object is
 initialized,
 passed by value to a function parameter, or
 returned by value from a function
Copy Constructor…

• A copy constructor declaration:


Identifier ( const Identifier& );
 Identifier is the class name.  In the definition of the
copy constructor, we
 perform a shallow copy of the non-resource instance
variables,
 allocate fresh freestore memory for the resource
instance variable(s), and
 copy data pointed to by the original object to the
freshly allocated memory pointed to by the new
object.
Assignment Operator
• An assignment operator copies data from an existing object
into an existing object.
Identifier& operator=(const Identifier&);
(Identifier: is the name of the class of the right operand) 

In the definition, we:


– check for self-assignment
– deallocate previously allocated freestore memory
– allocate new freestore memory
– copy resource source data to freshly allocated memory
– copy non-resource instance variables to destination
variables
No Copies Allowed

If you want to make it impossible for


other people to write code that makes
copies of your object, write a copy
constructor and an assignment
operator and make them private.
Custom iostream Operators

int main () {
ISBN foo = ISBN(“9330440556”);

// How does cout know what to do with


// our ISBN object foo?

cout << foo; // It doesn’t… yet.


}
Custom iostream Operators

• An object can interact with input and output


streams in the same way that primitive data
types interact. 
• The istream and ostream classes of the
iostream library support object-oriented input
and output.
Custom iostream Operators…

• We extend the functionality of the extraction


(>>) and the insertion (<<) operators to
objects of our own design by overloading the
operators to accept our objects as rights
operands. 
Overloading the << operator

class Student {
int no;
int semester;
char grade[M+1];
public:
Student();
friend ostream& operator<<(ostream& os,
const Student& s);
};
Overloading the << operator

ostream& operator<<(ostream& os,


const Student& st) { 

os << st.no << ' ' << st.semester


<< ' ' << st.grade << endl;

return os;

}
Overloading the << operator

Int main () {

Student hans(00212,”ABCDF”);
cout << hans; // now it works!

}
Cascading

• Cascading is the concatenation of several


variables in a single statement interspersed
with the appropriate operator.
• The insertion and extraction operators are
overloaded in the istream and ostream
classes so as to enable cascading. 
Cascading…

Card a, b, c, d, e;

// how does the + operator


// do this:
a = b + c + d + e;
We need 2 operators:

// This one is for the first pair:


Operator+(Card L, Card R);

// This one is for the second,


third, etc.
Operator+(int , Card R);
Overloading the + operator

int operator+(int lhs,Card &rhs) {


return lhs + valToInt(rhs.val);
}
int main () {
Card a ('A', 's');
Card b ('K', 'd');
Card c ('3', 'h');
Card d ('9', 's');
int foo;

foo = a + b + c + d; // foo = 33
}

int operator+(int lhs,Card &rhs) {


return lhs + valToInt(rhs.val);
}
Returning A Reference

• Returning a reference from a function has two


intrinsic benefits:
 efficiency
 creates an lvalue
• Returning a reference copies a single address. 
(Returning the value at that address may involve
copying many instance variables, possibly even
deep copying, which is much more time
consuming.)
Overloading the << operator: Cascading

ostream& operator<<(ostream& os,


const Student& st) { 

os << st.no << ' ' << st.semester


<< ' ' << st.grade << endl;

return os; // return a reference

}
Student nobita(13443,”BDCDF”);
Student doraemon(33333,”AABAD”);

cout << doraemon << ‘ ‘ << nobita;


When the first operator<< runs, it returns a reference
to a Student object , so the next << can also work.

ostream& operator<<(ostream& os,


const Student& st) { 
os << st.no << ' ' << st.semester
<< ' ' << st.grade << endl;
return os; // return a reference
}
lvalue Creation
• The term lvalue originates in the description of an
assignment expression. 
• An assignment expression consists of a left operand, the
assignment operator and a right operand.  The left
operand must occupy some memory location where the
value of the right operand may be stored.  The left
operand cannot be a constant or a temporary expression. 
• Examples of lvalues include:
 variables
 objects
 array elements
 functions that return references
Dangling References

• Returning a reference to a local variable or a


parameter received by value (these go out of
scope when the function returns control to its
caller) is called a dangling reference. 
Variable Scope : a function that does
nothing
void doNothing () {
int a, b, c;
a = 5; b = 6, c = 10;
int d = a * b * c;
// when the function closes a, b,
c, and d get ~deleted.
}
Variable Scope: Dangling References

Card * addCards(Card a, Card b, Card)


{
Card c;
c = a + b;
return &c; // this doesn’t work
// because c gets deleted
// after the function closes
}
Variable Scope: no dangling reference

void addCards(Card a,
Card b, Card * c ) {

*c = a + b;
return c; // this works
// it works because c comes from
// outside the function,
// so it doesn’t get deleted
// when the function closes.
}
String Input overflow

char foo [10];


int bar = 5;

cin >> foo; // user types 13 chars

cout << bar; // error – bar has been


// corrupted by extra
// characters from foo.
String Input overflow…

• The Solution
 The string class addresses this indefinite-size
problem.  An object of the string class accepts as
many characters as the user enters and allocates
as much memory as is needed to store the set of
characters. 
 The string class requires #include <string> for the
prototypes.
String Input overflow…

istream& getline(istream&, string&, char);  


• The string class has two member functions for
translating strings into null-terminated C-style
strings:
 length() - the number of characters in the string
 c_str() - the address of the null-terminated C-style
version of the string.
String Class Example

#include <string>

int main( ) {
string str;
getline(cin, str);

}
Conversion Operators

Sometimes we need to convert an object of one


class to an object of another data type.

Student::operator int() const{


return no;

Student::operator int() const{
return no;

int main() {
int n;
Student hans(1234, “ABABF”);

n = hans; //convert Student to int

cout << n; // what output?



}
Derived Data Type Conversions
Design Considerations

• Conversion operators should be used


sparingly and their implementations kept
trivial. 

• Too many conversion operators make your


code difficult to read. 
Single-Argument Constructors

Conversion operators define implicit conversions


from the data type of the current object to
another data type. 

To define a conversion from a data type to the


data type of the current object, we use single-
argument constructors. 
class Student {

public:
Student();
Student(int);
set(int no, char grades);
};

Student::Student(int no) {
set(no, "");
} // single argument constructor
Student::Student(int no) {
set(no, "");
} // single argument constructor

// convert int to Student


Student harry = 1234;

cout << harry;


How does the compiler know what to do
when it sees this:

Student harry = 1234;

?
Conversion Sequence…
Student harry = 1234; // ??
• In searching for a conversion the compiler steps
through definite stages.  The compiler looks for
 an exact match (for example, int to int, Student to
Student),
 a promoted match (for example, char to int, float to
double),
 a standard conversion match (for example, int to
double, int to float),
 a derived data type conversion match (for example,
int to Student). ( This is the one it uses for the
example shown above.)
Explicit Constructors

• To suppress implicit conversions by a single-


argument constructor, we qualify the constructor as
explicit
explicit ClassIdentifier(dataType);

• For an explicit single-argument constructor, we


need to write
harry = Student(1234); 
instead of
harry = 1234; 
explicit Student::Student(int no) {
set(no, "");
}

// doesn’t work
Student harry = 1234;

// works
Student harry = Student(1234);

Why would we want to use “explicit”?


?

You might also like