C++ data types

advertisement
C++ data types
•
Fundamental (or simple or scalar):
A data object of one of these types is a single object.
- int, double, char, bool, complex,
and the related types (unsigned, short, etc.)
- enumerations
•
Structured:
Collections of data
- arrays, structs, unions, classes, valarrays, bitsets
the containers and adapters in STL
Structs vs. Classes
Similarities
1. same syntax
2. Both used to model objects with
different attributes (characteristics) represented as
data members (also called fields or instance variables).
Thus, both used to process non-homogeneous data
sets.
Structs vs. Classes
Differences
1. C does not provide classes;
C++ provides both structs and classes.
2. Members of a struct by default are public
can be accessed outside the struct
by using the dot operator
Members of a class by default are private
cannot be accessed outside the struct
but can be explicitly declared public
C++ Classes
C++'s structs and classes model objects that have:
• Attributes (characteristics)
represented as data members
• Operations (behaviors)
represented as function members (methods).
classes
 new style of programming : Object-Oriented
Objects are self-contained,
Associated with their own operations
the I can do it myself principle
rather than being passed as a parameter to an external
function that operates on them and sends them back.
Common Forms of Declaring a Class
class ClassName
{
// private by default
Declarations of private members
public:
Declarations of public members
};
class ClassName
{
public:
//"interface" of class given 1st
Declarations of public members
private:
Declarations of private members
};
Notes on Declaring a Class
1. Data members are normally placed in the private section of a class;
Function members in the public section.
2. Some programmers prefer to put the private section first
Use the default access for classes
Omit the private: specifier
3. Other programmers put the public interface of the class first
and the hidden private details last.
(In the book, we use the latter approach)
4. Although not commonly done (poor technique),
a class may have several private and public sections;
the keywords private: and public: mark the beginning of each.
Access to Class Members
 A particular instance of a class is called an object :
ClassName object_name;
 Private members can be accessed only within the class
(except by friend functions to be described later).
 Public members can be accessed within or outside the class.
to access them outside the class, one must use the dot operator:
object_name.public_member_name
Class declarations are placed in a header file whose name is ClassName.h
Header file for class Time — Version 1
/** Time.h ----defines the data type Time with operations
Set:
To set the time
Display: To display the time
*/
#include <iostream>
using namespace std;
class Time
{ /******** Member functions ********/
public:
/* sets data members of(Time)object to specified values
* Receive: hours, minutes (in standard time)
*
AMPM ('A' if AM, 'P' if PM)
*/
void Set(unsigned hours, unsigned minutes, char am_pm);
Header file for class Time — Continued
/* Display displays time in standard and military format
*
using output stream out.
*
* Receive:
ostream out
* Output:
The time represented by Time object
*
for which this function invoked
***************************/
// const function: cannot modify data members
// good practice: protects data members from
//
accidental modification.
void Display(ostream & out) const;
private: // Data Members
unsigned myHours,
myMinutes;
char
myAMorPM;
// 'A' or 'P'
unsigned myMilTime;
// military time equivalent
};
// end of class declaration
Data Members: Why private?
"Hidden" data members
Cannot be accessed outside class
application programs must interact with an object through its interface
public member functions control interaction between programs and class.
Application program need not know about implementation!
Implementation may change
If interface is constant, programs using an object need not be changed.
What's wrong with tying application code to implementation details?
A change in implementation forces a change in the application code
Increased upgrade time.
Increased programmer cost
Decreased programmer productivity
Reduced profits due to
— Delayed releases/upgrades
— Loss of customer confidence in software reliability
Implementation of a Class
Class declaration contains
 Declaration of data members
 Prototypes (declaration) of member functions
Member functions are not usually placed in class declaration
 clutters up the interface
 definitions placed outside class header
 must tell compiler where the declaration/prototype is
Use the scope operator :: which has the form
ClassName::ItemName
(the qualified or full name of ItemName.)
Implementation of class Time — Version 1
// Time.cpp -- implements the Time member functions
#include "Time.h"
/* ToMilitary converts standard time to military time.
 Receive: hours, minutes, am_pm
 Return: The military time equivalent
 Could implement this utility function as private class method
*/
int ToMilitary (unsigned hours, unsigned minutes, char am_pm)
{
if (hours == 12)
hours = 0;
return hours * 100 + minutes + (am_pm == 'P' ? 1200 : 0);
}
void Time::Display(ostream & out) const
{
out << myHours << ':'
<< (myMinutes < 10 ? "0" : "") << myMinutes
<< ' ' << myAMorPM << ".M. ("
<< myMilTime << " mil. time)";
}
Implementation of class Time — Continued
void Time::Set(unsigned hours, unsigned minutes,
char am_pm)
{
// Check class invariant
if (hours >= 1 && hours <= 12 &&
minutes >= 0 && minutes <= 59 &&
(am_pm == 'A' || am_pm == 'P'))
{
myHours = hours;
myMinutes = minutes;
myAMorPM = am_pm;
myMilTime = ToMilitary(hours, minutes, am_pm);
}
else
cerr << "*** Can't set time with these values ***\n";
// Object's data members remain unchanged
}
Test driver for class Time
#include "Time.h"
#include <iostream>
using namespace std;
int main()
{
Time mealTime;
mealTime.Set(5, 30, 'P');
cout << "We'll be eating at ";
mealTime.Display(cout);
cout << endl;
}
Execution
We'll be eating at 5:30 P.M.
(1730 mil. time)
Object-Oriented Perspective
Procedural: send object off to some function for processing
OO: send a message to the object to operate on itself.
To set my digital watch to 5:30 P.M.,
I don't wrap it up and mail it off to Casio.
I push a button!
To display the time on my watch,
I don't wrap it up and mail it off to Casio and have them tell me what
time it is.
I have it display the time itself, perhaps pushing a button to turn on the
backlight so I can see it .
Class Constructors
constructing an object consists of:
 allocating memory for the object, and
 initializing the object.
In our example, after the declaration
Time mealTime;
memory has been allocated for object mealTime
but it's data members are not initialized
(likely to contain "garbage" values).
Need to:
 specify initial values for mealTime
 provide default values to be used if no initial values are specified.
Class Constructors - Properties
 names are always the same as the class name.
 initialize the data members of an object
with default values or values provided as arguments
 do not return a value
- have no return type (not even void).
 often simple and can be inlined
 called whenever an object is declared.
 If no constructor is given in the class, compiler supplies a default
- constructor which allocates memory and
- initializes it with some default (possibly garbage) value
A default constructor is one that is used when the declaration of an
object contains no initial values:
ClassName object_name;
Constructors for Time class
// Time.h
class Time
{
public:
/** Construct a class object (default).
* Precondition: A Time object has been declared.
* Postcondition: Time object is initialized to 12:00 A.M.;
**********************/
Time();
/* --- Construct a class object (explicit values).
* Precondition: A Time object has been declared.
* Receive:
Initial values initHours, initMinutes, and
*
initAMPM
* Postcondition: Time object are initialized to passed values
**********************/
Time(unsigned initHours, unsigned initMinutes, char initAMPM);
. . .
// other member function prototypes
private:
/********** Data Members **********/
. . .
}; // end of class declaration
Constructors for Time class - Implementation
inline Time::Time()
{
myHours = 12;
myMinutes = 0;
myAMorPM = 'A';
myMilTime = 0;
}
Time::Time(unsigned initHours, unsigned initMinutes, char initAMPM)
{
// Check class invariant
assert(initHours >= 1 && initHours <= 12 &&
initMinutes >= 0 && initMinutes <= 59 &&
(initAMPM == 'A' || initAMPM == 'P'));
myHours = initHours;
myMinutes = initMinutes;
myAMorPM = initAMPM;
myMilTime = ToMilitary(initHours, initMinutes, initAMPM);
}
Create and initializes 2 Time objects
Time
mealTime,
//default constructor
bedTime(11,30,'P'); //explicit-value constructor
Code:
mealTime.Display(cout);
cout << endl;
bedTime.Display(cout);
cout << endl;
Execution:
12:00 A.M. (0 mil. time)
11:30 P.M. (2330 mil. time)
Constructors for Time class - Default Parameters
Can combine both constructors into a single constructor function by
using default arguments:
Replace constructors in Time.h with:
/* --- Construct a class object.
Precondition: A Time object has been declared.
Initial values initHours, initMinutes, and
Receive:
initAMPM (defaults 12, 0, 'A')
Postcondition: Time object initialized to initHours,
initMinutes, and initAMPM , respectively.
---*/
Time(unsigned initHours = 12, unsigned initMinutes = 0,
char initAMPM = 'A');
Note: Any parameter with default argument must appear after all parameters
without default arguments.
Copy Operations
Two default copy operations are provided:
1. Copy in initialization (copy constructor)
2. Copy in assignment (assignment operator)
Each makes a (byte-by-byte) copy of the data
members of the object.
Called a bitwise or memberwise copy.
Examples:
Time t = bedTime; // copy constructor called
Time t(bedTime);
// copy constructor called
Both:
1. Allocate memory for t
2. Copy data members of bedTime so t is a copy of
bedTime
In contrast:
Time t = Time(11, 30, 'P');
calls the explicit-value constructor
to construct a (temporary) Time object and then
copies it (via the assignment operator) into t.
Access Member Functions
Data members are private: they cannot be accessed outside the class.
To make the values stored in some or all of these members accessible,
provide access member functions
Example:
provide access to myHours of class Time.
(access for the remaining members is analogous.)
simply retrieves the value stored in a data member
 inline
 prototype (and define) as a const function
// add to class Time
inline unsigned Time::Hour() const;
{ return myHours; }
Output and Input
Add output operation(s) to a class early
 use for debugging.
Example: overload operator<< for a Time object
cout << "We'll be eating at "
<< mealTime << endl;
instead of
cout << "We'll be eating at " ;
mealTime.Display(cout);
cout << endl;
Overloading operators
In C++,
operator  can be implemented with the function
operator()
— If a member function of a class C, and a is of type C,
the compiler treats a  b as
a.operator(b)
— If not a member function of a class C,
the compiler treats a  b as
operator(a, b)
Overloading Output Operator <<
Can operator<<() be a member function?
No, because the compiler will treat
cout << t
as
cout.operator<<(t)
which means that operator<<() is a member of class ostream!
Putting the prototype
ostream& operator<<(ostream& out, const Time& t);
inside the class declaration causes a compiler error like:
'Time::operator <<(ostream &, const Time &)'
must take exactly one argument
operator<<() as a member function of Time means that
it has the Time object as an (implicit) parameter,
so it needs only one formal parameter.
//If simple, inline definition in.h file
inline ostream& operator<<(ostream& out, const Time& t)
{
t.Display(out);
return out;
}
Why??
 out a reference parameter : ostream gets modified so must be passed back
 t a const reference parameter : avoid overhead of copying a class object
 return a reference to out: chain output operators
cout << t1 << endl << t2 << endl;
<< left-associative => operator<<(cout, t1) << endl << t2 << endl;
first function must return cout
=> cout << endl << t2 << endl;
=> operator<<(cout, endl) << t2 << endl;
Alternative:
declare operator<< to be a friend of class Time
//in header file
friend ostream& operator<<(ostream& out, const Time& t);
//in implementation file
ostream & operator<<(ostream & out, const Time & t)
{
out << t.myHours << ':'
<< (t.myMinutes < 10 ? "0" : "")
<< t.myMinutes
<< ' ' << t.myAMorPM << ".M. ("
<< t.myMilTime << " mil. time)";
return out;
}
Friend Functions
A function that a class declares as a friend is a
non-member function to which
the class has granted permission
to access members in its private sections.
Note: Because a friend function is not a function member:
• definition not qualified with class name and scope operator (::)
• receives the object on which it operates as a parameter
• uses the dot operator to access the data members.
Relational Operator<
Specification:
Receives: Two Time objects
Returns: True if the first Time object is less than the second; false otherwise.
Should operator< be a member function?
internal perspective: I compare myself with another Time object and
determine if I am less than that other object
external perspective: Two Time objects are compared to determine if the
first is less than the second.
OOP "I-can-do-it-myself" principle ( objects self-contained)
 use member functions whenever possible.
Rephrased specification:
Receives: A Time object (and the current object implicitly)
Returns: True if I (the Time object containing this function) am less than the
Time object received; false otherwise.
Relational Operator<
// Internal perspective : add to Time.h
class Time
{
public:
// member functions
...
/***** Relational operators *****/
/* operator< determines if one Time is less than another Time
Receive: A Time t (and the current object implicitly)
Return: True if time represented by current object is < t.
*/
bool operator<(const Time & t);
...
}; // end of class declaration
inline bool Time::operator<(const Time & t)
{ return myMilTime < t.myMilTime; }
Caveat: Operator Overloading
Internal perspective may be too restrictive for completely consistent use
e.g. for some objects a & b of some class PromoteD
a < b;
b < a;
// ok: operator syntax,
// equivalent to a.operator<(b)
// ok, same as b.operator(a)
a < 2;
// ok, given a constructor that
// promotes 2 to object of typepromoteD
// Statement then equivalent to a.operator<(2)
2 < a;
// ERROR.
2.operator<(a) has no meaning
Syntactically confusing to application programmer to
support a < 2 but disallow 2 < a.
 use friends
Overloaded Operator as Friend
external perspective: permits a < 2 and 2 < a (if 2 can be promoted)
class Time
{
public:
// member functions
...
/* operator<
Receive: Two Times t1 and t2
Return:
True if time t1 is less than time t2/
*/
friend bool Time::operator<(const Time& t1, const Time& t2);
...
};
// end of class declaration
inline bool operator<(const Time& t1, const Time& t2)
{ return t1.myMilTime < t2.myMilTime; }
Redundant Declarations
class Time might be used in programs, libraries, etc.
 it could be included several times in the same file
e.g.,
Program needs Time class, so it #includes "Time.h"
Program also needs library Lib, so it #includes "Lib.h"
. . . but Lib.h also #includes "Time.h"
 cause "redeclaration" errors during compiling.
How do we prevent the declarations in Time.h from being
included more than once in a file?
Conditional Compilation
Wrap the declarations in Time.h inside preprocessor directives
#ifndef TIME
Usually the name of the class in all caps
#define TIME
:
:
#endif
The first directive tests to see whether the identifier TIME has been defined.
If defined:
Proceed to second directive ( define TIME )
Continue to the #endif and beyond.
If not defined:
Preprocessor removes all code that follows
until a #elsif, #else, of #endif directive encountered.
Download