210 likes | 361 Views
HKUST Summer Programming Course 2008. Using Member Functions and Data Members. Overview. Accessing member functions Inspector Function (Accessor) Mutator Function Function Overloading Friend Functions/Class Static Member Functions Static Data Member Data Sharing - extern
E N D
HKUST SummerProgramming Course 2008 Using Member Functions and Data Members
Overview • Accessing member functions • Inspector Function (Accessor) • Mutator Function • Function Overloading • Friend Functions/Class • Static Member Functions • Static Data Member • Data Sharing - extern • Changing Constant Objects - mutable
Accessing member functions • Use member access operator (.) Word vowel(“a”, 12); vowel.addfreq(3); // call a member function // in Word class • Use dereference member access operator (->) // a pointer to a Word object Word* boy = new Word(“boy”, 2); vowel->addfreq(1); • It is equal to a deference operator plus a member access operator, i.e. (*boy).addfreq(1);
Inspector Function (Accessor) • An inspector function allows programmers to read (but not modify) data members of the class. • It has another name called “accessor” or “gettor”. • Usually it has a “get” as prefix and declared as a constant function. int Word::getfreq() const { return frequency; } char* Word::getword() const { if (str != NULL) { char *temp = new char [strlen(str)+1]; strcpy(temp, str); return temp; } else { return NULL; } }
Mutator Function • A mutator function (or called “settor”) modifies data members of the class. • Usually it has a “set” as prefix. • You can use “const” and pass-by-reference(&) to avoid unnecessary copying and prevent accidental change of parameter content. int Word::setfreq(const int& new_freq) { frequency = new_freq; return frequency; // return the new frequency // but it is not necessary, // you can use “void” instead }
Function Overloading • We can define a few functions using the same name with different kinds of argument. • That will increase the usability of your class. E.g. void Word::setword(const char* new_word) { … } void Word::setword(const string& new_word) { … } • Both of them has the name “setword” but accept different argument. User can use “char*” or “string” in this function.
Function Overloading • When overloading functions, we have to pay attention to their signature. • A function’s signature includes its parameter list and const-ness of function (except its return type), i.e. int Word::addfreq(int amount); int Word::addfreq(float amount); int Word::addfreq(int amount) const; • All of the above are valid overloaded functions. • Be careful, const function and non-const function are considered different. (1st and 3rd example)
Friend Functions/Class • A friend functionof a class is an ordinary (nonmember) function except that • it has access to the private members of the objects. • We usually place friend function prototypes in the “public” section. • General guidelines: • Use a nonmember/friend function only if the task being performed involves multiple objects. • Whether an ordinary nonmember function or a friend function should be used is a matter of efficiency and personal taste.
Friend Functions/Class void print_date(const Date& today, const Clock& time) { cout << today.day << “-” << today.month << “-” << today.year; cout << “ “ << time.hour << “:” << time.minute << endl; } • To let the above function work, we can put its prototype to both Date and Clock class. class Date { public: friend void print_date(const Date&, const Clock&); … }; // class Clock is similar
Friend Function/Class • Friend class is similar to friend functions. You can put the declare of a class as friend class in another class. • Usually when a class is controlled by another class, it will let the controller class to touch its private members, e.g. • In a linked-list, the Node class can friend the List class to let it touch its data. class Node { public: friend class List; … }; • One important thing: If you friend a class, that class can access all your private data, but not in reverse.
Static Member Functions • For example, we have a clock class like this, class Clock { private: int hour, minute; public: Clock(int h = 0, int m = 0) : hour(h), minute(m) { } void tick(); void print(); }; // Global functions that will call the clock constructor Clock make_clock_hhmm(int hhmm) { return Clock(hhmm/100, hhmm%100); } Clock make_clock_minutes(int min) { return Clock(min/60, min%60); }
Static Member Functions • In order to let user have two ways to create a clock (in hhmm or in minutes, both are int type), we created two global functions to help our user. • It seems good, but it has some drawbacks, • They are not belong to class, so it is easy to forget them when we update the codes in the class. • They are global functions, so they can’t access private data of a class. (or we can use friend functions.)
Static Member Functions • A better solution is to use static member functions. class Clock { … public: static Clock HHMM(int hhmm) {…} static Clock minutes(int i) {…} }; • Static methods of a class are really global functions with a “funnyname”. • They belong to the class, and can access private data. • NO object is required to invoke them, they exist whenever the class exists.
Static Member Functions class Clock { private: int hour, minute; Clock(int h, int m) : hour(h), minute(m) { } public: Clock() : hour(0), minute(0) { } void tick(); void print(); static Clock HHMM(int hhmm) { return Clock(hhmm/100, hhmm%100); } static Clock minutes(int i) { return Clock(i/60, i%60); } }; // Now we can set clocks Clock c1; // 0:00 Clock c2 = Clock::HHMM(120); // 1:20 Clock c3 = Clock::minutes(120); // 2:00
Static Data Member • Classes can also have static data members. • Static data members are really global variables with a funny name. • They also follow access control (public and private), just like normal variables. class Car { private: static int num_cars; // count total number of // Car objects produced int total_km; public: Car():total_km(0) { ++num cars; } ~Car() { --num cars; } static int cars_produced() { return num_cars; } };
Static Data Member #include "car.h" int Car::num cars = 0; // definition of static member int main() { cout << Car::cars_produced() << endl; // prints 0 Car vw; Car bmw; cout << Car::cars_produced() << endl; // prints 2 return 0; } /* It can count the number of objects produced. But remember, if you don’t provide your own copy constructor and assignment operator(=), the counting will be wrong. Because the default copy constructor don’t know how to count objects. */
Static Data Member • Static variables are shared among all objects of the same class. • They do not take up space inside an object. • Static variables, though act like global variables, cannot be initialized in the class definition. Instead, they must be defined outside the class definition. • Usually the definitions of static variables are put in the class implementation (.cpp) file.
Static Data Member • Static member functions can only use static data members of the class. • Because static methods do not have the implicit this pointer like regular member functions, e.g. • A regular member function of Car like void drive(int km) { total_km += km; } after compilation becomes: void Car::drive( Car* this, int km){ this->total_km+=km; } • On the other hand, a static method of Car like static int cars_produced() { return num_cars; } after compilation becomes: int Car::cars_produced() { return num_cars; }
Data Sharing - extern • Extern means a variable (or function) has an external linkage with a variable (or function) in another file. • External variable declaration: extern int global_var; • External function declaration extern void reverse_print(const char* s); • The above two are declaration only, they are not the real variable. They don’t have memories assigned. • The actual variable (or function) is defined in another file.
// main.cpp extern int global_var; extern void rev_print(const char* s); int main(int argc, const char* argv[]) { cout << “global var = “ << global_var << endl; cout << “input string backwards = “; rev_print(argv[1]); } // Output: // global var = 23 // input string backwards = … // otherfile.cpp // compile it with main.cpp int global_var = 23; void rev_print( const char* s){ for (int j = strlen(s)-1; j >= 0; --j) { cout<< s[j]; } cout<< endl; } // Actual variables and functions // are defined here Data Sharing - extern
Changing Constant Objects - mutable • The concept is easy: when a variable is declared as mutable, its content can be changed even if the object is a constant. class Word { public: char* str; mutable int frequency; // can be changed }; const Word movie(“Superman”, 0); // const object movie.frequency += 1; //it is ok