More about Classes Andy Wang Object Oriented Programming

  • Slides: 61
Download presentation
More about Classes Andy Wang Object Oriented Programming in C++ COP 3330

More about Classes Andy Wang Object Oriented Programming in C++ COP 3330

Friends and Members Motivating example Suppose we want to compare two Fraction objects Fraction

Friends and Members Motivating example Suppose we want to compare two Fraction objects Fraction f 1(1, 2), f 2(2, 4); If (Equals(f 1, f 2)) cout << “The fractions are equaln”;

One Possible Solution bool Equals(Fraction x, Fraction y) { return (x. Get. Numerator() *

One Possible Solution bool Equals(Fraction x, Fraction y) { return (x. Get. Numerator() * y. Get. Denominator() == y. Get. Numerator() * x. Get. Denominator()); } Need many accessor calls Equals() is not a member function of the Fraction class Not very efficient

A More Efficient Way bool Equals(Fraction x, Fraction y) { return (x. numerator *

A More Efficient Way bool Equals(Fraction x, Fraction y) { return (x. numerator * y. denominator == y. numerator * x. denominator; } However, Equals() does not have access to private data

An Alternative—friend The keyword friend allows a class to grant full access to a

An Alternative—friend The keyword friend allows a class to grant full access to a function or even another class Access to all the class’s members Including the private section To grant friend status, declare the friend function anywhere in the class declaration A friend function is neither public nor private A friend function is not a member function It is invoked just like a normal function with access to private members

Example Fraction Class http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 1/ Equals() friend

Example Fraction Class http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 1/ Equals() friend function Add() friend function A driver function

frac. h class Fraction { friend bool Equals(Fraction x, Fraction y); friend Fraction Add(Fraction

frac. h class Fraction { friend bool Equals(Fraction x, Fraction y); friend Fraction Add(Fraction x, Fraction y); public: … private: … };

frac. cpp Note: no keyword friend here #include <iostream> … bool Equals(Fraction x, Fraction

frac. cpp Note: no keyword friend here #include <iostream> … bool Equals(Fraction x, Fraction y) { return (x. numerator * y. denominator == y. numerator * x. denominator); } Note: no keyword friend here Fraction Add(Fraction x, Fraction y) { int num = x. numerator * y. denominator + y. numberator * x. denominator; int denom = x. denominator * y. denominator; return Fraction(num, denom); } …

driver. cpp #include <iostream> #include “frac. h” using namespace std; int main() { Fraction

driver. cpp #include <iostream> #include “frac. h” using namespace std; int main() { Fraction f 1, f 2, f 3, f 4 cout << “Enter fraction f 1: “; f 1. Input(); cout << “Enter fraction f 2: “; f 2. Input(); cout << “nf 1 = “; f 1. Show(); cout << “nf 2 = “; f 2. Show(); cout << “nn”;

driver. cpp if (Equals(f 1, f 2)) cout << “f 1 and f 2

driver. cpp if (Equals(f 1, f 2)) cout << “f 1 and f 2 are equaln”; else cout << “f 1 and f 2 are NOT equaln”; f 3 = Add(f 1, f 2); cout << “f 1 + f 2 = “; f 3. Show(); cout << ‘n’; return 0; }

Another Option Use a member function if (f 1. Equals(f 2)) cout << “The

Another Option Use a member function if (f 1. Equals(f 2)) cout << “The fractions are equaln”; f 1 is a calling object f 2 is a parameter

Equals() Member Function One possible definition bool Fraction: : Equals(Fraction f) { return (numerator

Equals() Member Function One possible definition bool Fraction: : Equals(Fraction f) { return (numerator * f. Get. Denominator() == f. Get. Numerator() * denominator); } Another definition bool Fraction: : Equals(Fraction f) { return (numerator * f. denominator == f. numerator * denominator); } Objects of a class can access each other’s private member data

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 2/ Equals() member function Add()

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 2/ Equals() member function Add() member function Sample driver program

frac. h class Fraction { public: … bool Equals(Fraction f); Fraction Add(Fraction f); private:

frac. h class Fraction { public: … bool Equals(Fraction f); Fraction Add(Fraction f); private: … };

frac. cpp include <iostream> … bool Fraction: : Equals(Fraction f) { return (numerator *

frac. cpp include <iostream> … bool Fraction: : Equals(Fraction f) { return (numerator * f. denominator == f. numerator * denominator); } Fraction: : Add(Fraction f) { int num = numerator * f. denominator + f. numberator * denominator; int denom = denominator * f. denominator; return Fraction(num, denom); } …

driver. cpp #include <iostream> #include “frac. h” using namespace std; int main() { Fraction

driver. cpp #include <iostream> #include “frac. h” using namespace std; int main() { Fraction f 1, f 2, f 3, f 4; cout << “Enter fraction f 1: “; f 1. Input(); cout << “Enter fraction f 2: “; f 2. Input(); cout << “nf 1 = “; f 1. Show(); cout << “nf 2 = “; f 2. Show(); cout << “nn”;

driver. cpp if (f 1. Equals(f 2)) cout << “f 1 and f 2

driver. cpp if (f 1. Equals(f 2)) cout << “f 1 and f 2 are equaln”; else cout << “f 1 and f 2 are NOT equaln”; f 3 = f 1. Add(f 2); cout << “f 1 + f 2 = “; f 3. Show(); cout << ‘n’; return 0; }

Member vs. Friend friend Fraction Add(Fraction f 1, Fraction f 2); Parameters are pass-by-value

Member vs. Friend friend Fraction Add(Fraction f 1, Fraction f 2); Parameters are pass-by-value Original objects will not be changed Fraction Add(Fraction f); The private member data of the calling object can be changed

Conversion Constructors Recall that some of the built-in types allow automatic type conversions int

Conversion Constructors Recall that some of the built-in types allow automatic type conversions int x = 5; double y, z; y = x; // legal, via automatic conversion z = x + y; // legal, via automatic conversion Conversion constructor A constructor with one parameter Fraction(int n) converts int to Fraction n/1

Explicit and Implicit Conversions Fraction f 1, f 2 // create fraction objects; f

Explicit and Implicit Conversions Fraction f 1, f 2 // create fraction objects; f 1 = Fraction(4); // explicit call to conversion constructor f 2 = 10; // implicit call to conversion constructor // equivalent to f 2 = Fraction(10) f 1 = Add(f 2, 5); // implicitly converts 5 to Fraction 5/1 Fraction(int n, int d = 1) counts as a conversion constructor Since the second parameter is optional Suppress implicit conversion explicit Fraction(double d); // will NOT be used for // automatic conversions

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 3/

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 3/

frac. h class Fraction { public: … Fraction(int n, int d=1); explicit Fraction(double d);

frac. h class Fraction { public: … Fraction(int n, int d=1); explicit Fraction(double d); … private: … };

frac. cpp … Fraction: : Fraction(int n, int d) { if (Set. Value(n, d)

frac. cpp … Fraction: : Fraction(int n, int d) { if (Set. Value(n, d) == false) Set. Value(0, 1); } // dummy function // NOT trying to convert d to an equivalent fraction Fraction: : Fraction(double d) { Set. Value(static_cast<int>(d), 1); } …

driver. cpp … int main() { Fraction f 1, f 2, f 3, f

driver. cpp … int main() { Fraction f 1, f 2, f 3, f 4; f 1 = 5; // implicit conversion f 2 = Fraction(6); // explicit conversion f 3. Set. Value(3, 8); f 4 = Add(f 3, 10); // implicit conversion // same as f 2 = Add(f 3, Fraction(10))); cout << “nf 1 = “; f 1. Show(); cout << “nf 2 = “; f 2. Show(); cout << “nf 3 = “; f 3. Show(); cout << “nf 4 = “; f 4. Show();

driver. cpp // f 1 = 5. 6 // will NOT work f 1

driver. cpp // f 1 = 5. 6 // will NOT work f 1 = Fraction(5. 6) // WILL work return 0; }

Using const in Class Specifies what is not allowed to change, within some scope

Using const in Class Specifies what is not allowed to change, within some scope Clarifies the intent of the code to other users Affects how certain items can be used

L-Value vs. R-Value L-value = r-value; x = 10 vs. 10 = x? L-value

L-Value vs. R-Value L-value = r-value; x = 10 vs. 10 = x? L-value can appear on the left-hand side of an assignment R-value can appear on the right-hand side of an assignment

const Reference Parameters If an object is passed by value, a copy is made

const Reference Parameters If an object is passed by value, a copy is made Any R-value can be sent into the call friend Fraction Add(Fraction f 1, Fraction f 2); If an object is passed by reference (without const), no copy is made Only an L-value can be sent into the call More efficient, especially for large objects However, the object may be changed friend Fraction Add(Fraction &f 1, Fraction &f 2)

const Reference Parameters If we don’t want to change the original objects, use const

const Reference Parameters If we don’t want to change the original objects, use const reference parameters friend Fraction Add(const Fraction &f 1, const Fraction &f 2);

const Member Functions void Func(int x) const // const member function Function may NOT

const Member Functions void Func(int x) const // const member function Function may NOT change the calling object itself Can ONLY be done to member functions of a class Member function will NOT change the member data of that object Object y will remain the same state before and after this const member function call Yadda y; y. Func(5); // object y // will NOT change the data of y const must go on the declaration and the definition

const Member Functions Should be used whenever appropriate for good class design Constructors initialize

const Member Functions Should be used whenever appropriate for good class design Constructors initialize the object Would not be const functions Mutators change member data Would not be const functions Pure accessor functions retrieve member data Would typically be const functions Functions for printing (e. g. , Show(), Display()) Would be good candidates for const functions

Examples of friend Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 4/ Uses

Examples of friend Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 4/ Uses const reference parameters on the friend functions Uses const on all member functions that don’t change the member data

frac. h class Fraction { friend bool Equals(const Fraction &x, const Fraction &y); friend

frac. h class Fraction { friend bool Equals(const Fraction &x, const Fraction &y); friend Fraction Add(const Fraction &x, const Fraction &y); public: Fraction(); Fraction(int n, int d=1); void Input(); void Show() const; int Get. Numerator() const; int Get. Denominator() const; bool Set. Value(int n, int d); double Evaluate() const; private: int numerator, denominator; };

frac. cpp … bool Equals(const Fraction &x, const Fraction &y) {…} Fraction Add(const Fraction

frac. cpp … bool Equals(const Fraction &x, const Fraction &y) {…} Fraction Add(const Fraction &x, const Fraction &y) {…} Fraction: : Fraction() {…} Fraction: : Fractoin(int n, int d) {…} void Fraction: : Input() {…} void Fraction: : Show() const {…} int Fraction: : Get. Numerator() const {…} int Fraction: : Get. Denominator() const {…} bool Fraction: : Set. Value(int n, int d) {…} double Fraction: : Evaluate() const {…}

Example with Equals and Add Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra

Example with Equals and Add Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/fra c 5/ const is used on Add() and Equals(), so that the calling objects will not be changed

frac. h class Fraction { public: Fraction(); Fraction(int n, int d=1); void Input(); void

frac. h class Fraction { public: Fraction(); Fraction(int n, int d=1); void Input(); void Show() const; Fraction f will int Get. Numerator() const; not be int Get. Denominator() const; changed bool Set. Value(int n, int d); double Evaluate() const; bool Equals(const Fraction &f) const; Fraction Add(const Fraction &f) const; Numerator and private: denominator int numerator, denominator; will not be }; changed

frac. cpp … bool Fraction: : Equals(const Fraction &f) const {…} Fraction: : Add(const

frac. cpp … bool Fraction: : Equals(const Fraction &f) const {…} Fraction: : Add(const Fraction &f) const {…} Fraction: : Fraction() {…} Fraction: : Fractoin(int n, int d) {…} void Fraction: : Input() {…} void Fraction: : Show() const {…} int Fraction: : Get. Numerator() const {…} int Fraction: : Get. Denominator() const {…} bool Fraction: : Set. Value(int n, int d) {…} double Fraction: : Evaluate() const {…}

Declaring const Objects Need to be initialized at the same line const int SIZE

Declaring const Objects Need to be initialized at the same line const int SIZE = 10; const double PI = 3. 1415; Objects can also be declared as const Constructor will be involved An object’s state cannot be changed afterwards const Fraction ZERO; // fixed at 0/1 const Fraction FIXED(3, 4); // fixed at ¾

const Objects Can only call const member functions FIXED. Show() cout << FIXED. Evaluate();

const Objects Can only call const member functions FIXED. Show() cout << FIXED. Evaluate(); int n = ZERO. Get. Numberator(); int d = ZERO. Get. Denominator(); Examples of illegal operations (compiler errors) FIXED. Set. Value(5, 7); ZERO. Input(); If an object has no constant function (e. g. , the earliest Fraction class example), ALL calls will result in compiler errors

Example: No const Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/thi ng 1/

Example: No const Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/thi ng 1/ const function calls in main() will not work.

thing. h class Thing { public: Thing(); Thing(int h, int w); void Show(); void

thing. h class Thing { public: Thing(); Thing(int h, int w); void Show(); void Set(int h, int w); int Get. Height(); int Get. Weight(); private: int height, weight; };

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() {

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() { height = weight = 0; } Thing: : Thing(int h, int w) { height = h; weight = w; } void Thing: : Show() { cout << “Height = “ height << “tt. Weight = “ << weight << ‘n’; } void Thing: : Set(int h, int w) { height = h; weight = w; } Int Thing: : Get. Height() { return height; } Int Thing: : Get. Weight() { return weight; }

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int temp 1, temp 2; const Thing t 1(4, 100); // all member function calls will fail to compile // since t 1 is const t 1. Show(); t 1. Set(10, 300); temp 1 = t 1. Get. Height(); temp 2 = t 1. Get. Weight(); return 0; }

Example: const Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/thi ng 2/ const

Example: const Member Functions http: //www. cs. fsu. edu/~myers/cop 3330/examples/class 2/thi ng 2/ const member function calls will compile

thing. h class Thing { public: Thing(); Thing(int h, int w); void Show() const;

thing. h class Thing { public: Thing(); Thing(int h, int w); void Show() const; void Set(int h, int w); int Get. Height() const; int Get. Weight() const; private: int height, weight; };

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() {

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() { height = weight = 0; } Thing: : Thing(int h, int w) { height = h; weight = w; } void Thing: : Show() const { cout << “Height = “ height << “tt. Weight = “ << weight << ‘n’; } void Thing: : Set(int h, int w) { height = h; weight = w; } Int Thing: : Get. Height() const { return height; } Int Thing: : Get. Weight() const { return weight; }

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int temp 1, temp 2; const Thing t 1(4, 100); t 1. Show(); t 1. Set(10, 300); // compilation error temp 1 = t 1. Get. Height(); temp 2 = t 1. Get. Weight(); return 0; }

const Member Data Member data can also be declared const Tricky syntax Not legal

const Member Data Member data can also be declared const Tricky syntax Not legal to initialize member data in a class declaration class Thing { public: … private: int y = 0; const int Z = 10; }; // ILLEGAL

Another Try thing. h class Thing { public: … private: int y; const int

Another Try thing. h class Thing { public: … private: int y; const int Z; }; thing. cpp Thing: : Thing() { y = 0; Z = 10; // ILLEGAL }

Solution Initialization list return_type function(parameters) : initialization_list { // function body } The initialization

Solution Initialization list return_type function(parameters) : initialization_list { // function body } The initialization list is in the following format const_member_data_1(value_1), const_member_data_2(value_2), …, const_member_data_n(value_n)

thing. h class Thing { public: … private: int height, weight; const int LIMIT;

thing. h class Thing { public: … private: int height, weight; const int LIMIT; static const int SIZE = 10; // static member // shared by all objects of this class };

thing. cpp … Thing: : Thing() : LIMIT(10) { height = weight = 0;

thing. cpp … Thing: : Thing() : LIMIT(10) { height = weight = 0; } Thing: : Thing(int h, int w) : LIMIT(h) { height = h; weight = w; } … void Thing: : Set(int h, int w) { height = h; weight = w; if (height > LIMIT) height = LIMIT; } …

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int

main. cpp #include <iostream> #include “thing. h” using namespace std; int main() { int temp 1, temp 2; Thing t 1(12, 100); t 1. Show(); cout << “n”; t 1. Set(13, 400); t 1. Show(); cout << “n”; return 0; }

Destructors Like constructors, but with a ~ in front Cannot have parameters Only one

Destructors Like constructors, but with a ~ in front Cannot have parameters Only one destructor per class ~Fraction() Called automatically before an object is deallocated by the system (goes out of scope) Perform clean-up tasks (memory deallocation) before an object is deallocated

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/destr 1/

Example http: //www. cs. fsu. edu/~myers/cop 3330/examples/destr 1/

thing. h class Thing { public: Thing(); Thing(int x); ~Thing(); private: int data; };

thing. h class Thing { public: Thing(); Thing(int x); ~Thing(); private: int data; };

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() {

thing. cpp #include <iostream> #include “thing. h” using namespace std; Thing: : Thing() { data = 0; cout << “Running default constructor: data = “ << data << ‘n’; }

thing. cpp Thing: : Thing(int x) { data = 0; cout << “Running constructor

thing. cpp Thing: : Thing(int x) { data = 0; cout << “Running constructor (with parameter): data = “ << data << ‘n’; } Thing: : ~Thing() { cout << “Running destructor: data = “ << data << ‘n’; }

main. cpp #include <iostream> #include “thing. h” using namespace std; void Func() { cout

main. cpp #include <iostream> #include “thing. h” using namespace std; void Func() { cout << “** Creating object A (local variable in function ** n”; Thing A(25); }

main. cpp int main { cout << “** Declaring object A **n” Thing A;

main. cpp int main { cout << “** Declaring object A **n” Thing A; { cout << “** Declaring B (in new block) **n”; Thing B(6); cout << “** Calling function Func() **n”; Func(); cout << “** We have returned from Func() **n”; cout << “** Leaving local block **n”; }

main. cpp { cout << “** Declaring C (in new block) **n”; Thing C(10);

main. cpp { cout << “** Declaring C (in new block) **n”; Thing C(10); cout << “** Leaving local block **n”; } return 0; }