Upload
milo-terence-joseph
View
218
Download
1
Embed Size (px)
DESCRIPTION
Member data references Suppose that I have a class: class Date{ char month, day; int year; … Member functions can refer to data members without any other qualification: int getDay(){return day;} Member functions may have access to several copies of the member data Consider the copy constructor
Citation preview
Copyright © 2006-2012 Curt Hill
Classes RevisitedSeveral topics not taught the
first time
Topics • Several topics that still need
attention• The this pointer• Friends of classes• Operator overloading• Inline functions
Copyright © 2006-2012 Curt Hill
Copyright © 2006-2012 Curt Hill
Member data references• Suppose that I have a class:class Date{ char month, day; int year; …
• Member functions can refer to data members without any other qualification:int getDay(){return day;}
• Member functions may have access to several copies of the member data
• Consider the copy constructor
Copyright © 2006-2012 Curt Hill
Date Copy ConstructorDate::Date(const Date & that){ month = that.month; day = that.day; year = that.year; }
• All the data of Date is private, but methods may access:– Member data of their own class– Their own local variables– Member data of parameters that are of
the same class
Copyright © 2006-2012 Curt Hill
One problem• How does a method refer to the whole
class?– In the Date class, month, day and year at
once?• For each class there is a pointer, this,
which refers to all of the instance data• this is a keyword• It is a constant pointer referring to the
entire structure (class)• Member functions that will return the
entire class will use it
Copyright © 2006-2012 Curt Hill
Copy Constructor RevisitedDate::Date(const Date & that){ this->month = that.month; this->day = that.day; this->year = that.year; }
• This is equivalent to previous• Also the wrong way to do it since it
involves extra typing
Copyright © 2006-2012 Curt Hill
Using this• We use this whenever the entire
class is referenced inside the method• Suppose we need a local variable of
the same type:Date d = *this;
• This is most commonly done in operator overloads of operators like– = and compound assignments– ++ --– Arithmetic operators
Copyright © 2006-2012 Curt Hill
Review of Visibility• There are three visibilities in C++
classes• Private
– Only class code may access• Protected
– Only class code and derived class code may access
• Public• Any code may access
• Access means to use a variable or function directly
Copyright © 2006-2012 Curt Hill
Three Types of Code
DerivedClass
Class
Client
Copyright © 2006-2012 Curt Hill
Visibility Again• The default visibility of a class is
private• Presence of one of the visibility
keywords forces that visibility until the next visibility keyword for all those things declared in between
• Friends are something of an exception to these rules– The fourth visibility
Copyright © 2006-2012 Curt Hill
Friends• A class may grant extra privileges to
other things outside the class• Either functions or classes• A friend function is a stand alone
function that can access any item within a class
• A friend class is another class that can access any item within the class
Copyright © 2006-2012 Curt Hill
Friends• Each class may designate other
classes or functions as friends• A friend has access to properties and
methods of any visibility• A friend function usually needs to
access private data but cannot be member function
• A friend class allows two or more classes to act as one
Copyright © 2006-2012 Curt Hill
Declaring a friend function• A friend function is declared in the
class header with friend as a prefix to the prototype:friend void fun(…);
• It is not a member function so outside the class it is declared as an ordinary function void fun(…);– The reserved word friend is not repeated
• The visibility of friends are always public
Copyright © 2006-2012 Curt Hill
Syntax Notes• The friend prefix must only be used
inside the class• It is not repeated in the defintion, nor
is it needed in other declarations• Sometimes forward declarations are
needed
Copyright © 2006-2012 Curt Hill
Declaring a friend class• A class is different than a function• The declaration is still prefixed:friend class other;
• Again outside the class friend is left off:class other{…
• Incidentally classes may also be declared with a prototype: class other;
• This declares but does not define
Copyright © 2006-2012 Curt Hill
Examples• The best examples of friend functions
are overloaded operators involving two different classes– One of these will be considered later in
the presentation• Dynamic data structures usually are
the best examples of friend classes• We will consider the linked list next
Copyright © 2006-2012 Curt Hill
A Linked List• Two classes:class List;class ListItem { Data d; // carried data ListItem * next; friend class List; ListItem(); // private default }; // everything is privateclass List{ ListItem * root; public: void add(Data d); bool isPresent(Data d); …};
Copyright © 2006-2012 Curt Hill
Linked List• Two separate classes are needed since there
are two different structures– An iterator class is often helpful
• The client is given no access at all to the ListItem
• Everything is done through the List• List must be the friend of ListItem, but
ListItem does not need any privileges in List– Mutual friends are legal and sometimes needed
• The linked list often needs an iterator which will demonstrate three classes being friends
Copyright © 2006-2012 Curt Hill
Friend Visibility• A friend function cannot be hidden• It does not matter where the friend is
defined as a friend it is public by virtue of its declaration outside of the class
• It may access the class private, protected or public items
Copyright © 2006-2012 Curt Hill
Best Practices• Friends are considered by some to be a
security error in C++– They grant access to class internals to non-
class code• If a friend only needs access to one
class, it should probably be a member function
• Generally only use friends when access to two different classes is needed– The function should be a friend of one or
both
Copyright © 2006-2012 Curt Hill
Operator Overload Overview• Operator overloads allow a class to
redefine what an operator does• This is a very powerful way to
integrate the class into the language– Makes it much more intuitive
• Each operator then is a special kind of function
Copyright © 2006-2012 Curt Hill
Review: Function Overloading• C++ was one of the first languages to
allow– Previous languages depended on function
name only• The signature of the function
determined which was called• The signature is:
– The function name– The parameter list– Not the return value
Copyright © 2006-2012 Curt Hill
Function call matching• Suppose that we have two functions:int fn(int a, int & b);float fn(float a, float & b);
• A call exists:float f,g; int i,j;fn(f,g);
• The call uses name and parameter types to match to second fn
• Since we do not have to use the result we cannot depend on it
Copyright © 2006-2012 Curt Hill
Ambiguity• Suppose that:int fn(float a, double & b);int fn(double a, float & b);
• A call like:float x,y;fn(x,y);is ambiguous– It is equally distant from each call– It will be flagged as an error
• Operator overloading has same problem
Copyright © 2006-2012 Curt Hill
Operator Overloading• The same scheme as function name
overloading• We generate a function whose name
is an operator• The function must have the right
number of parameters for that type of operator
Copyright © 2006-2012 Curt Hill
Operator Overload• Like functions most operators may
be overloaded• The compiler will determine the
function to use by the parameter number and type
• This is also true with operators
Copyright © 2006-2012 Curt Hill
C++ Operators• There are more than 40• These include the common ones:
+ - = * <• The uncommon ones:
? : .* ->*• The named ones:
new delete sizeof• Only a five cannot be overloaded
. .* :: ?: sizeof all of which are compile time operators
• The preprocessor # and ## cannot be changed
Copyright © 2006-2012 Curt Hill
Restrictions on Overloading• No new ones can be added
– No new characters or reserved words• No change in an operators:
– arity (number of operands) – precedence – associativity– These changes would make the compiler
front end very problematic• Assignment operator can only be a
member function (not a friend)
Copyright © 2006-2012 Curt Hill
Caveats• Overloading operators can ruin or
improve readability• Since any operator in a program
could be overloaded we should only make operator overloads that are clear and intuitive
• Most helpful for making a class look like it is built-in to the language
Copyright © 2006-2012 Curt Hill
Type of Overloads• Stand alone functions• Friend functions• Overloading an operator in a function is
generally a bad idea– It cannot involve a class – Hurts readability– Nice way to demonstrate how to get started– Friends are member functions will add to this
Copyright © 2006-2012 Curt Hill
Form• All overloaded operators are
functions• They take one or two parameters• Return a value• The name is the reserved word
operator followed by the operator to be overloaded
• Example on next screen concatenating two strings
Copyright © 2006-2012 Curt Hill
+ as concatenationchar * operator + (char * fir, char * sec){ int len = strlen(fir)+strlen(sec); char * res = new char[len+10]; strcpy(res,fir); strcat(res,sec);
return res; }
Copyright © 2006-2012 Curt Hill
Discussion• There are two + operators• Which one was overloaded above?• The number of parameters caused
this to overload the addition operator• How many parameters does a
member function have?
Copyright © 2006-2012 Curt Hill
Another Example• Suppose a stand-alone function to
overload % for doubles is wanted:double operator %(double a, double b);
• The function name is now two things:– The reserved word operator– The operator to be used
• The number of parameters must match what the operator expects
Copyright © 2006-2012 Curt Hill
Matching• From the time when this definition is
seen the compiler looks at all % operators
• If it finds two integers around it, then it will use the standard operator
• If it finds two doubles, then it will use this
• If it does not find one of these, it will try to use casts to get to one of these, provided there are no others
Copyright © 2006-2012 Curt Hill
Arity• Operators comes in three arities:
– Unary– Binary– Ternary
• There is only one ternary and it cannot be overloaded
• The % only comes in binary form so it must have two parameters
• The + may be unary or binary, so its overload may have one or two parameters
Copyright © 2006-2012 Curt Hill
Method Parameters• Consider the Date class again:int getDay()const{return day;}
• How many parameters does this method have?
• Both zero and one• Clearly zero
– There is nothing in the parameter list• Also one
– The instance data counts as a parameter
Copyright © 2006-2012 Curt Hill
Consider the Call• How is the getDay method called?
Date d;…int day = d.getDay();
• Without the instance d there is no call to getDay
• The instance data acts as a hidden parameter
• To do this with a friend function it must have one parameter
Copyright © 2006-2012 Curt Hill
Parameter Counts• A unary operator such as !
– Needs one parameter from a friend function– The non-static member function will appear to
be parameterless• A binary operator such as /
– Needs two parameters from a friend function • The first parameter is to left, the second to the right
of operator– The non-static member function will appear to
have one• The instance data will be to the left of operator, the
parameter to the right
Copyright © 2006-2012 Curt Hill
Friend Example• Inside the Date class one might see
this:friend bool operator == (const Date & l, const Date & r);
• Outside the class the definition of the function would look like an ordinary stand-alone function
Copyright © 2006-2012 Curt Hill
When to use Friends• The previous is not necessarily a
good example of when to use a friend– A member function would generally be
preferred for this• A friend function is usually used
when two classes are used by the same function and the two are unrelated
• Such as ofstreams and the simple types both use <<
Copyright © 2006-2012 Curt Hill
A Better Friend Example• Recall the class:class Date{ char month, day; int year; friend ofstream & operator << (ofstream &, Date);
• Implementation is shown in next slide
Copyright © 2006-2012 Curt Hill
Implementationofstream & operator << (ofstream & outf, Date d){ return outf << int(d.month) << “/” << int(d.day) << “/” << d.year;}
Copyright © 2006-2012 Curt Hill
Discussion• friend is not repeated• This is not a recursive routine
– Even though it both defines and uses <<
• It involves two classes, neither of which is dominant over the other– It uses public functions of ofstream but
the private data of Date• Could this be a member function?
– No, item to left is not local object
Copyright © 2006-2012 Curt Hill
Member functions as operators• Member functions may also overload
operators• The important trick to remember is that the
local class data constitutes one parameter– Thus a unary operator appears to have no
parameters– A binary operator cites the second parameter
only• The usage looks the same as a friend
– There is no need for the instance .– The item to left of binary operator is the
instance you get– If it is a unary operator that is the instance you
get
Copyright © 2006-2012 Curt Hill
Examples• Suppose we wish to overload the + • Item on left is Date and item on right
is an int• Result is the integer days added to
the date• This could be done as friend or non-
static method• Only one of these would actually be
used otherwise we have ambiguity
Copyright © 2006-2012 Curt Hill
As a Friend• In the header:class Date { …friend Date operator + (Date,int);
• Implemented: Date operator + (Date d,int days){ d.days += days; d.correct(); // adjust for day return d;}
Copyright © 2006-2012 Curt Hill
As a Method• In the header:class Date { …Date operator + (int) const;
• Implemented: Date Date::operator + (int dy) const{ Date d = *this; d.days += dy; d.correct(); // adjust for day return d;}
Copyright © 2006-2012 Curt Hill
Discussion• Any of these would handle the
following call:Date today, later;later = today + 10;
• However, none of them would handle: later = 10 + today;
• This requires an additional friend:Date operator + (int,Date);
• Or a single integer constructor and a two date overload of +
Symmetry• Since the first parameter must be
class for the member function we would likely provide a stand alone function:Date operator + (int i,Date d){ return d+i;}
• This needs no privileges
Copyright © 2006-2012 Curt Hill
Copyright © 2006-2012 Curt Hill
Asymmetry • The Date is an unusual semi-numeric
– Adding/subtracting an integer makes sense
– Adding a date does not– Subtracting make sense to get an
integer but not a Date• Other really numeric types (eg. a
fraction) would have constructors– One for each numeric type so that the
add could always have two fractions
Example =• The assignment operator must be a
member function• Recall that the assignment operator
always returns a value• Thus it is like the copy constructor
with the addition of the return
Copyright © 2006-2012 Curt Hill
Copyright © 2006-2012 Curt Hill
Assignment Operator• In the class:Date operator = (const Date &);
• ImplementedDate Date::operator = (const Date & that){ month = that.month; day = that.day; year = that.year; return *this; }
• The parameter would be better as const reference
• The return type would be better as Date &
Copyright © 2006-2012 Curt Hill
Instance data• For binary operators the instance
data is the operand to the left of the operator– The parameter is for the operand to
the right of the data• For unary operators there is no
method parameter and the instance data is all there is– Most unary operators have their
operand to right of operator
Copyright © 2006-2012 Curt Hill
Where does this not work?• Is there a unary operator that can
appear on either side of its operand? • ++ and --• How do we distinguish which is
which?• A syntactical kludge
Copyright © 2006-2012 Curt Hill
Kludge (klooj)• A quick, messy, but functional fix or
workaround to a problem• Bad code that works but is barely
readable, overly complex and/or unmaintainable
• A computer system that is constituted of poorly matched elements or of elements originally intended for other applications
• A clumsy or inelegant solution to a problem
Copyright © 2006-2012 Curt Hill
Prefix and postfix unary operators
• In Curt’s Occasionally Humble Opinion the way C++ determines if a unary is a prefix or postfix operator is a kludge
• Fortunately ++ and -- are the only ones that can be both
• The prefix operator as a member function has no argument:– operator ++ ();
• The postfix operator has a dummy argument that is not used:– operator ++(int);
Copyright © 2006-2012 Curt Hill
Example: Method• As methods to be implementedDate Date::operator++(){ // prefix operator day++; correct(); return *this; }
Date Date::operator++(int){ // postfix operator Date temp = *this; // before day++; correct(); return temp; }
• Notice that the parameter need not be named
Copyright © 2006-2012 Curt Hill
Unary friend operator functions• Similar to members, but with one more parameter
– Prefix has one, Postfix has two, one a dummy– The parameter must be by reference
• Example:Date operator++(Date & d){ // prefix operator d.day++; d.correct(); return *this; }
Date operator++(Date & d,int){ // postfix operator Date temp = d; // before d.day++; d.correct(); return temp; }
Copyright © 2006-2012 Curt Hill
Friends and Methods• When to use member functions and when
to use friends?• If function needs access to private data of
more than one class, a friend is required• Friends cannot be concealed so private
functions need a member function• If the handling of the parameters is in any
way symmetric then a friend is implied• Friends may change values but usually do
not• Usually a member function overloads side
effect operators
Copyright © 2006-2012 Curt Hill
Constant Operators• Most operators have no side effects• Do yourself a favor:
– Make the parameter passage mechanism constant reference
– Declare the member function as const• Thus:Date Date::operator + (const Date & d) const {…}
Copyright © 2006-2012 Curt Hill
Comparisons • The comparison operators are
commonly overloaded• Only the programmer of the class
knows how to do the comparison• Typically only code two, such as ==
and <• Then use those to code the others
Copyright © 2006-2012 Curt Hill
Date Comparison Example// Declared in .h, defined in .cppbool operator == (const Date & rhs)const;bool operator < (const Date & rhs) const;
// Defined only in .Hbool operator > (const Date & rhs) const{ return !(*this == rhs || *this < rhs);}bool operator >= (const Date & rhs)const{ return ! (*this < rhs);}bool operator <= (const Date & rhs)const{ return (*this == rhs || *this < rhs);}bool operator != (const Date & rhs)const{ return !(*this == rhs);}
Copyright © 2006-2012 Curt Hill
Efficiency• Accessor functions are generally very
simple– Often just a return or assignment
• Recall getDay: int getDay(){return day;}
• In such a case the function call overhead is several machine language instructions– While the actual code may only be one
or two• There is a way to get around this
Copyright © 2006-2012 Curt Hill
The inline directive• inline is a reserved word that may
prefix a function or method• It is a directive (suggestion) that the
call be omitted and the code expanded inline
• What happens is that the function call is replaced by the function body
• This generally reduces the number of instructions but has no effect on actions performed
Copyright © 2006-2012 Curt Hill
In other words• Classes promote information hiding
– Generally conceal the data and publicize the methods that access it
• For example we may want to declare a member function that gives access to component
• Instead of making that component public we give read only access through a function– However such a function is very likely very simple
• If it is only a question of returning a value from the class then the function call overhead may end up larger than the work the function does– Thus the need for inline
• The function is not really a function– When it is called we generate the code inline
Copyright © 2006-2012 Curt Hill
Space and Speed• Our old friends space and speed are
often traded off – Reducing one may make the other larger
• The inline directive will always reduce the number of instructions executed
• It may make the code larger– There are now multiple copies of the
subroutine body• If the code is shorter than function call
protocol then it is a win-win situation
Copyright © 2006-2012 Curt Hill
inline Example• Recall getDay: int getDay(){return day;}
• It now becomes:inline int getDay(){return day;}
Copyright © 2006-2012 Curt Hill
Directives• C/C++ have several directives like inline• They are always suggestions to the
compiler– The compile may ignore them with impunity
• They should not affect any program characteristic other than performance or size
• Another such directive is the register prefix of a simple variable– This requests that this variable will be heavily
used and should reside in a register
Copyright © 2006-2012 Curt Hill
More on inline• Inline is not restricted to classes• It can be used for any function
– However it is most likely to be used with classes
– We very often have a trivial function or two
• Example:• inline int snerd(...) {do this and that}