1.31k likes | 1.32k Views
Chapter 11: More About Classes and Object-Oriented Programming. Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda. Topics. 11.1 The this Pointer and Constant Member Functions 11.2 Static Members 11.3 Friends of Classes
E N D
Chapter 11: More About Classes and Object-Oriented Programming Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda
Topics 11.1 The this Pointer and Constant Member Functions 11.2 Static Members 11.3 Friends of Classes 11.4 Memberwise Assignment 11.5 Copy Constructors 11.6 Operator Overloading 11.7 Type Conversion Operators
Topics (continued) 11.8 Convert Constructors 11.9 Aggregation and Composition 11.10 Inheritance 11.11 Protected Members and Class Access 11.12 Constructors, Destructors, and Inheritance 11.13 Overriding Base Class Functions
11.1 The this Pointer and Constant Member Functions • thispointer: - Implicit parameter passed to a member function - points to the object calling the function • Is passed as a hidden argument to all non-static member functions • Can be used to access members that may be hidden by parameters with same name • constmember function: - does not modify its calling object
Using the this Pointer Can be used to access members that may be hidden by parameters with the same name: class SomeClass { private: int num; public: void setNum(int num) { this->num = num; } };
Constant Member Functions • Declared with keyword const • When const follows the parameter list, int getX()const the function is prevented from modifying the object. • When constappears in the parameter list, int setNum (const int num) the function is prevented from modifying the parameter. The parameter is read-only.
11.2 Static Members • Each instance of a class has its own copies of the class’s instance (member) variables • Objects box1 and box2 of class Rectangle each have their own values for length and width • Static member variable: • One instance of variable for the entire class • Shared by all objects of the class • Static member function: • Can be used to access static member variables • Can be called before any class objects are instantiated
Static Member Variables • Must be declared in class with keyword static: class IntVal { public: intVal(int val = 0) { value = val; valCount++ } int getVal(); void setVal(int); private: int value; static int valCount; };
Static Member Variables 2) Must be defined outside of the class: class IntVal { //In-class declaration static int valCount; //Other members not shown }; //Definition outside of class int IntVal::valCount = 0;
static member variable Contents of Tree.h 1 // Tree class 2 class Tree 3 { 4 private: 5 static int objectCount; // Static member variable. 6 public: 7 // Constructor 8 Tree() 9 { objectCount++; }10 11 // Accessor function for objectCount12 int getObjectCount() const13 { return objectCount; }14 };15 16 // Definition of the static member variable, written17 // outside the class.18 int Tree::objectCount = 0; Static member declared here. Static member defined here. C++: Classes & Objects -2
Three Instances of the Tree Class, Only One objectCount Variable C++: Classes & Objects -2
Static Member Variables 3) Can be accessed or modified by any object of the class: Modifications by one object are visible to all objects of the class: IntVal val1, val2; valCount 2 val1 val2
Static Member Functions 1)Declared with static before return type: class IntVal { public: static int getValCount() { return valCount; } private: int value; static int valCount; };
Static Member Functions 2) Can be called independently of class objects, through the class name: cout << IntVal::getValCount(); 3) Because of item 2 above, the this pointer cannot be used 4) Can be called before any objects of the class have been created 5) Used mostly to manipulate static member variables of the class
Modified Version of Tree.h 1 // Tree class 2 class Tree 3 { 4 private: 5 static int objectCount; // Static member variable. 6 public: 7 // Constructor 8 Tree() 9 { objectCount++; }10 11 // Accessor function for objectCount12 static int getObjectCount() 13 { return objectCount; }14 };15 16 // Definition of the static member variable, written17 // outside the class.18 int Tree::objectCount = 0; Now we can call the function like this:cout << "There are " << Tree::getObjectCount()<< " objects.\n"; C++: Classes & Objects -2
Budget Class version 1 • Budget class gathers budget information from all the divisions of a company • The static member, corpBudget, holds the overall corporate budget • The function addBudget adds the passed amount to the division total as well as the corporate total C++: Classes & Objects -2
Budget version 1 • In main, we call getCorpBudget by specifying an object of the Budget class: divisions[0].getCorpBudget() • Note that a static method can not specify const • You can also call the function as Budget::getCorpBudget() but then the function would have to be static and could not be const C++: Classes & Objects -2
Budget version 1 #ifndef BUDGET_H #define BUDGET_H class Budget { private: static double corpBudget; // Static member double divisionBudget; // Instance member public: Budget() { divisionBudget = 0; } void addBudget(double b) { divisionBudget += b; corpBudget += b; } double getDivisionBudget() const { return divisionBudget; } double getCorpBudget() const // not defined static otherwise could not be const { returncorpBudget; } // therefore requires an object to be called }; // Definition of static member variable corpBudget double Budget::corpBudget = 0; #endif C++: Classes & Objects -2
Budget version 1 #include <iostream> #include <iomanip> #include "Budget.h" using namespace std; int main() { int count; // Loop counter const int NUM_DIVISIONS = 4; // Number of divisions Budget divisions[NUM_DIVISIONS]; // Array of Budget objects // Get the budget requests for each division. for (count = 0; count < NUM_DIVISIONS; count++) { double budgetAmount; cout << "Enter the budget request for division "; cout << (count + 1) << ": "; cin >> budgetAmount; divisions[count].addBudget(budgetAmount); } // Display the budget requests and the corporate budget. cout << fixed << showpoint << setprecision(2); cout << "\nHere are the division budget requests:\n"; for (count = 0; count < NUM_DIVISIONS; count++) { cout << "\tDivision " << (count + 1) << "\t$ "; cout << divisions[count].getDivisionBudget() << endl; } cout << "\tTotal Budget Requests:\t$ "; cout << divisions[0].getCorpBudget() << endl; return 0; } C++: Classes & Objects -2
Budget Class version 2 • Here a static function, mainOffice, is found • This allows the inclusion of a budget for the main office in addition to the individual divisions • The function can be called even before any objects of the Budget class have been instantiated C++: Classes & Objects -2
Budget version 2 #ifndef BUDGET_H #define BUDGET_H class Budget { private: static double corpBudget; // Static member variable double divisionBudget; // Instance member variable public: Budget() { divisionBudget = 0; } void addBudget(double b) { divisionBudget += b; corpBudget += b; } double getDivisionBudget() const { return divisionBudget; } double getCorpBudget() const { return corpBudget; } static void mainOffice(double); // Static member function }; #endif C++: Classes & Objects -2
Budget version 2 THIS IS FILE BUDGET.CPP #include "Budget.h" // Definition of corpBudget static member variable double Budget::corpBudget = 0; //********************************************************** // Definition of static member function mainOffice. * // This function adds the main office's budget request to * // the corpBudget variable. * //********************************************************** void Budget::mainOffice(double moffice) { corpBudget += moffice; } C++: Classes & Objects -2
Budget version 2 // Display corporate and division budgets cout << fixed << showpoint<< setprecision(2); cout << "\nHere are the division budget requests:\n"; for (count=0; count<NUM_DIVISIONS; count++) { cout<<"\tDivision "<< (count+1)<< "\t$"; cout<<divisions[count].getDivisionBudget()<< endl; } cout << "\tTotal Budget Requests:\t$ "; cout << divisions[0].getCorpBudget()<< endl; return 0; } #include <iostream> #include <iomanip> #include "Budget.h" using namespace std; int main() { int count; // Main office budget request double mainOfficeRequest; const int NUM_DIVISIONS = 4;// # of divisions //Get the main office's budget request. //No instances of Budget class have been defined cout << "Enter the main office's budget: "; cin >> mainOfficeRequest; Budget::mainOffice(mainOfficeRequest); // An array of Budget objects. Budget divisions[NUM_DIVISIONS]; // Get the budget requests for each division. for (count = 0; count < NUM_DIVISIONS; count++) { double budgetAmount; cout << "Enter the division budget request "; cout << (count + 1) << ": "; cin >> budgetAmount; divisions[count].addBudget(budgetAmount); } C++: Classes & Objects -2
Budget version 2 • What would you need to do in order to store the amount of the main office budget request as a static number and then print it out at the end of the report before the division budgets? • Declare static variable mainOffice in Budget class • Initialize mainOffice in Budget.cpp • Add mainOffice += moffice; to addMainOffice • Add double static getMainOffice() { return mainOffice; } to Budget.h C++: Classes & Objects -2
11.3 Friends of Classes • Friend function: a function that is not a member of a class, but has access to private members of the class • A friend function can be a stand-alone function or a member function of another class • It is declared a friend of a class with the friend keyword in the function prototype of the class granting it access
Friend Function Declarations • Friend function may be a stand-alone function: class aClass { private: int x; friend void fSet(aClass &c, int a); }; void fSet(aClass &c, int a) { c.x = a; }
Friend Function Declarations 2) Friend function may be a member of another class: class aClass { private: int x; friend void OtherClass::fSet (aClass &c, int a); }; class OtherClass { public: void fSet(aClass &c, int a) { c.x = a; } };
friend Function Declarations • In the following example, the addBudget function of class AuxilliaryOffice has been declared a friend in the Budget class • The auxiliary office (perhaps in another country) makes a separate budget request which must be added to the overall corporate budget • The friend declaration tells the compiler that the function is to be granted access to Budget’s private members • In Auxil.h there is a forward declaration of the Budget class • This tells the compiler that a class named Budget will be declared later in the program. This is needed because the compiler will process Auxil.h before it processes the Budget class declaration C++: Classes & Objects -2
Budget.h version 3 #ifndef BUDGET_H #define BUDGET_H #include "Auxil.h" // Budget class declaration class Budget { private: static double corpBudget; // Static member variable double divisionBudget; // Instance member variable public: Budget() { divisionBudget = 0; } void addBudget(double b) { divisionBudget += b; corpBudget += b; } double getDivisionBudget() const { return divisionBudget; } double getCorpBudget() const { return corpBudget; } // Static member function static void mainOffice(double); // Friend function friend void AuxiliaryOffice::addBudget(double, Budget &); }; #endif C++: Classes & Objects -2
Budget.cpp version 3 #include "Budget.h" double Budget::corpBudget = 0; // Definition of static member variable //********************************************************** // Definition of static member function mainOffice. * // This function adds the main office's budget request to * // the corpBudget variable. * //********************************************************** void Budget::mainOffice(double moffice) { corpBudget += moffice; } C++: Classes & Objects -2
Auxil.h Auxil.cpp #include "Auxil.h" #include "Budget.h" //********************************************************* // Definition of member function mainOffice. // This function is declared a friend by the Budget class. // It adds the value of argument b to the static corpBudget // member variable of the Budget class. //********************************************************* void AuxiliaryOffice::addBudget(double b, Budget &div) { auxBudget += b; div.corpBudget += b; } #ifndef AUXIL_H #define AUXIL_H // Forward declaration of Budget class class Budget; // Aux class declaration class AuxiliaryOffice { private: double auxBudget; public: AuxiliaryOffice() { auxBudget = 0; } double getDivisionBudget() const { return auxBudget; } void addBudget(double, Budget &); }; #endif C++: Classes & Objects -2
Main.cpp part 1 #include <iostream> #include <iomanip> #include "Budget.h" using namespace std; int main() { int count; // Loop counter double mainOfficeRequest; // Main office budget request const int NUM_DIVISIONS = 4; // Number of divisions // Get the main office's budget request. cout << "Enter the main office's budget request: "; cin >> mainOfficeRequest; Budget::mainOffice(mainOfficeRequest); Budget divisions[NUM_DIVISIONS]; // Array of Budget objects. AuxiliaryOffice auxOffices[4]; // Array of AuxiliaryOffice // Get the budget requests for each division and their auxiliary offices. for (count = 0; count < NUM_DIVISIONS; count++) { double budgetAmount; // To hold input // Get the request for the division office. cout << "Enter the budget request for division "; cout << (count + 1) << ": "; cin >> budgetAmount; divisions[count].addBudget(budgetAmount); C++: Classes & Objects -2
Main.cpppart 2 // Get the request for the auxiliary office. cout << "Enter the budget request for that division's\n"; cout << "auxiliary office: "; cin >> budgetAmount; auxOffices[count].addBudget(budgetAmount, divisions[count]); } // Display the budget requests and the corporate budget. cout << fixed << showpoint << setprecision(2); cout << "\nHere are the division budget requests:\n"; for (count = 0; count < NUM_DIVISIONS; count++) { cout << "\tDivision " << (count + 1) << "\t\t$"; cout << divisions[count].getDivisionBudget() << endl; cout << "\tAuxiliary office:\t$"; cout << auxOffices[count].getDivisionBudget() << endl << endl; } cout << "Total Budget Requests:\t$ "; cout << divisions[0].getCorpBudget() << endl; return 0; } C++: Classes & Objects -2
Friend Class Declaration • An entire class can be declared a friend of a class: class aClass {private: int x; friend class frClass; }; class frClass {public: void fSet(aClass &c,int a){c.x = a;} int fGet(aClass c){return c.x;} };
Friend Class Declaration • If frClass is a friend of aClass, then all member functions of frClass have unrestricted access to all members of aClass, including the private members. • The Budget class could make the Auxilliary Office class its friend by declaring friend class AuxilliaryOffice; • In general, restrict the property of Friendship to only those functions that must have access to the private members of a class.
11.4 Memberwise Assignment • Can use = to assign one object to another, or to initialize an object with an object’s data • Examples (assuming class V): V v1, v2; . // statements that assign . // values to members of v1 v2 = v1; // assignment means: copy all member values from v1 and assign to the corresponding member variables of v2 V v3 = v2; // initialization
11.5 Copy Constructors • Special constructor used when a newly created object is initialized to the data of another object of same class • Default copy constructor copies field-to-field • Default copy constructor works fine in many cases
Copy Constructors • Special constructor used when a newly created object is initialized to the data of another object of same class • Default copy constructor copies field-to-field • Default copy constructor works fine in many cases C++: Classes & Objects -2
Copy Constructors Problem: what if object contains a pointer? #include <cstring> class PersonInfo { private: char *name; int age; public: PersonInfo(char *n, int a) { name = new char[strlen(n) + 1]; strcpy(name, n); age = a; } ~PersonInfo() { delete [] name; } const char *getName() { return name; } int getAge() { return age; } }; C++: Classes & Objects -2
Copy Constructors • A potential problem with this class lies with the pointer member • The constructor dynamically allocates a section of memory and copies a string to it PersonInfo person1(“John Smith”,30); • If we perform the assignment PersonInfo person2 = person1; person2’s constructor is not called so a separate section of memory is not allocated for person2’s name member C++: Classes & Objects -2
Copy Constructors • Both pointers will point to the same address • If either of the two objects change the string, it will be reflected in both objects • If one object is destroyed, the remaining object’s pointer will still reference this section of memory although it should no longer be used Dynamically allocated memory pointer1’s name pointer John Smith pointer2’s name pointer C++: Classes & Objects -2
Copy Constructors • If you include a method in the class void setName(char *n){strcpy(name, n); } and then include person1.setName(“Ira R”); in the main program, both objects will again have the same name if you invoke the function getName() for person1 and person2 C++: Classes & Objects -2
Copy Constructors • What we really want is to create a copy of the dynamically allocated memory and have person2’s pointer point to it • This is accomplished by using a copy constructor
Copy Constructors • When the assignment operator is used to initialize person2 with the contents of person1, person1’s object is passed as an argument to person2’s object’s copy constructor • Takes a reference parameter to another object of the same class
Copy Constructors • Because copy constructor's are required to use reference parameters, they have access to their argument’s data • Since the purpose of the copy constructor is to make a copy of the argument, there is no reason the constructor should modify the argument’s data • Thus, it is a good idea to specify the keyword const in the parameter list PersonInfo(const PersonInfo & obj)
Programmer-Defined Copy Constructors • The copy constructor avoids problems caused by memory sharing • Can allocate separate memory to hold new object’s dynamic member data • Can make new object’s pointer point to this memory • Copies the data, not the pointer, from the original object to the new object
Copy Constructor Example class CpClass { int *p; public: CpClass(const CpClass &obj) { p = new int; *p = *obj.p; } CpClass(int v=0) { p = new int; *p = v; } ~CpClass(){delete p;} };