Download presentation
Presentation is loading. Please wait.
Published byBonnie Carson Modified over 9 years ago
1
Class Miscellanea Details About Classes
2
Review We’ve seen that a class has two sections: class Temperature { public: //... public members private: //... private members }; Anything that should be accessible to users of the class should be declared in the public section. Anything else should be declared in the private section.
3
Private Members The private section should contain a class’s data, plus any “utility” function members useful for implementing the class’s function members, but inappropriate for outside users. class Temperature { public: private: int Compare(const Temperature & temp2) const; double myMagnitude; char myScale; };
4
Object State Each class object has its own copy of each data member. Temperature temp1(212, ‘F’), temp2(100, ‘C’); An object’s data members’ values make up its state. Each object can have a distinct state. F myMagnitude myScale temp1 212 C myMagnitude myScale temp2 100
5
Class Scope A class member (data or function) can be directly accessed by any class function member or friend. // member inline char Temperature::Scale() const { return myScale; // private access } Class friends are not function members, but are “normal” functions with permission to access the private section. // friend inline istream & operator>>(istream & in, Temperature & temp) { in >> myMagnitude >> myScale; }
6
Public Members The public section should contain a class’s operations. class Temperature { public: Temperature(); Temperature(double magnitude, char scale); double Magnitude() const; char Scale() const; Temperature Fahrenheit() const; Temperature Celsius() const; Temperature Kelvin() const; friend istream & operator>>(istream & in, Temperature & temp); friend ostream & operator<<(ostream & out, const Temperature & temp); private: //... private members };
7
Class Interface The public operations (and a few default ones) make up the interface, or way that a program can use the class. #include “Temperature.h” //... Temperature temp1; // declare cin >> temp1; // input double itsMagnitude = temp1.Magnitude(); // read char itsScale = temp1.Scale(); // members Temperature temp2 = temp1.Kelvin(); // convert cout << temp2; // output
8
Interfaces (Ct’d) With a few exceptions, an operation not in a class’s interface cannot be applied to a class object. if (temp1 == temp2) // error! //... Since operator== is not defined for Temperature objects, the compiler has no means of knowing how they should be compared. Temperature temp1(212, ‘F’), temp2(100, ‘C’); if (temp1 == temp2) // true or false?
9
Utilities int Temperature::Compare(const Temperature & t2) const { Temperature leftTemp = Kelvin() // me in K Temperature rightTemp = t2.Kelvin(); // t2 in K return left.Magnitude() - right.Magnitude(); } We can always implement such operations ourselves. If we first define a nifty utility function to compare myself with another Temperature object: Compare() returns: –0 if I am equal to t2, –a negative value if I am less-than t2, and –a positive value if I am greater than t2.
10
Operations bool Temperature::operator==(const Temperature & temp2) { return Compare(temp2) == 0; // true iff I == temp2 } Then we can easily define the relational operators: bool Temperature::operator!=(const Temperature & temp2) { return Compare(temp2) != 0; // true iff I != temp2 } bool Temperature::operator<(const Temperature & temp2) { return Compare(temp2) < 0; // true iff I < temp2 } //...
11
Assignment For any user-defined class, C++ provides a default assignment operator (operator=). #include “Temperature.h” //... Temperature temp, saveTemp; cin >> temp; saveTemp = temp; // default assignment //... This default operation simply copies the members of the object to the right of the = into the members of the object to the left of the =.
12
A Problem A program can consist of multiple files. Suppose a programmer (or programming team) unwittingly #includes a class in two different places? When main.h is compiled, an error will be generated, because the declaration of SomeClass will be compiled more than once. class SomeClass { //... }; SomeClass.h #include “SomeClass.h” class AnotherClass { //... }; AnotherClass.h #include “SomeClass.h” #include “AnotherClass.h” int main() { //... }; main.h
13
An Ugly Solution #ifndef TEMPERATURE #define TEMPERATURE //... #include directives class Temperature { //... details omitted }; //... inline definitions #endif The solution is to use a new directive named and “wrap” the class declaration as follows: The solution is to use a new directive named #ifndef and “wrap” the class declaration as follows: When an directive is processed, if the identifer following it is not defined, compilation proceeds normally. When an #ifndef directive is processed, if the identifer following it is not defined, compilation proceeds normally. But if it is defined, then all subsequent code is skipped until a,, or directive appears. But if it is defined, then all subsequent code is skipped until a #else, #elif, or #endif directive appears.
14
An Ugly Solution #ifndef TEMPERATURE #define TEMPERATURE //... #include directives class Temperature { //... details omitted }; //... inline definitions #endif The solution is to use a new directive named and “wrap” the class declaration as follows: The solution is to use a new directive named #ifndef and “wrap” the class declaration as follows: So the first time the file is processed, TEMPERATURE is undefined, and execution proceeds as usual. The first thing following the is a directive that defines the identifier TEMPERATURE. The first thing following the #ifndef is a #define directive that defines the identifier TEMPERATURE. The class declaration is then processed normally.
15
An Ugly Solution #ifndef TEMPERATURE #define TEMPERATURE //... #include directives class Temperature { //... details omitted }; //... inline definitions #endif The solution is to use a new directive named and “wrap” the class declaration as follows: The solution is to use a new directive named #ifndef and “wrap” the class declaration as follows: The second the file is processed, TEMPERATURE is defined, and everything between there and the is skipped. The second the file is processed, TEMPERATURE is defined, and everything between there and the #endif is skipped. While it isn’t elegant, this ensures that the class declaration is processed just once, regardless of what programmers do.
16
The Bottom Line It is “good form” to always wrap a class declaration this way, using the uppercase name of the class: This will prevent SomeClass (or AnotherClass) from being declared more than once, regardless of what a programmer does. #ifndef SOME_CLASS #define SOME_CLASS class SomeClass { //... }; #endif SomeClass.h #ifndef ANOTHER_CLASS #define ANOTHER_CLASS #include “SomeClass.h” class AnotherClass { //... }; #endif AnotherClass.h #include “SomeClass.h” #include “AnotherClass.h” int main() { //... }; main.h
17
A Final Detail class Temperature { //... private: double myMagnitude; char myScale; }; The classes we have seen thus far have “normal” data members: Each class object has its own “local” data members: F myMagnitude myScale temp1 212 C myMagnitude myScale temp2 100
18
Question Suppose we want class Temperature to keep track of how many Temperature objects have been declared? One way to do so is to use a static data member: class Temperature { public: private: double myMagnitude; char myScale; static int tempCounter; }; int Temperature::tempCounter = 0; Static data members must be initialized externally (outside of the constructor), in the manner shown.
19
Constructors Each constructor can then increment this counter, so that each new will be counted: Each constructor can then increment this counter, so that each new Temperature will be counted: inline Temperature::Temperature() { myMagnitude = 0.0; myScale = ‘C’; tempCounter++; } inline Temperature::Temperature(double magnitude, char scale) { //... validity-checking omitted myMagnitude = magnitude; myScale = scale; tempCounter++; }
20
Static Members We can then add a function member to display the value of this counter: We can then add a Count() function member to display the value of this counter: inline int Temperature::Count() const { return tempCounter; } Now, the expression: cout << Temperature::Count() << endl; will display the number of objects currently in existence. will display the number of Temperature objects currently in existence. Static members are sometimes called class variables because they belong to the class, not its objects.
21
Destructors class Temperature { public: //... ~Temperature(); private: //... }; inline Temperature::~Temperature() { tempCounter--; } To remain accurate, our counter must be decremented each time a is destroyed. To remain accurate, our counter must be decremented each time a Temperature is destroyed. To do this, we can add a destructor function, whose name is the name of the class preceded by tilde (~):
22
Destructor Details An object’s destructor is called at the end of its scope. Like a constructor, a destructor has no return-type. Unlike a constructor, a destructor can have no parameters so it cannot be overloaded with multiple definitions (a class can have only one destructor function). Destructors are only needed when some action is needed (often “cleanup”) at the end of an object’s lifetime, such as ensuring the consistency of a static member, deallocating memory allocated by a constructor, and so on.
23
Summary Data members can be “normal” or static. –Normal data members are local to each class object. –Static data members are shared by all class objects. Data members should be declared as private. Function members can be declared –private, for utility functions –public, for operations on the class The public operations on a class make up its interface.
24
Summary (Ct’d) To avoid “redeclaration” errors, “wrap” every class: #ifndef CLASS_NAME #define CLASS_NAME //... #include directives class ClassName { //... details omitted }; //... inline definitions #endif and the class declaration will only be processed once.
25
Summary (Ct’d) A class destructor is a function member: –that has no return-type (like a constructor) –whose name is the name of the class preceded by a tilde (~) –that is called automatically at the end of an object’s lifetime –that is only needed when some action must be taken at the end of an object’s lifetime.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.