63
Strings and Classes

10.pdf

Embed Size (px)

DESCRIPTION

C++

Citation preview

Strings and Classes

Classes in C++ - Intro -- Encapsulation -- Interface vs. Implementation -- Member Functions -- Constructors

2

Object-Oriented Programming

3

At the heart of the O-O programming is: 1) Every operation is a message, sent to an object (to which, as a response, a function is being executed)

2) Everything is an object, instance of some class

3) It is in the definition of the class that we put The structure of the objects/instances

(these are the data members) The code executed in response to a message (these are the member functions)

So far, Program = collection of functions… However, as programs get larger, it becomes increasingly

difficult to maintain a large collection of functions. Moreover, it often becomes necessary to use the dreaded, awful, costly, error-prone and deadly practice of

USING GLOBAL VARAIBLES

Object-Oriented Programming

4

Object-Oriented Programming

Recall: global variables are those defined outside of all functions – so all functions have access to them.

But…

5

Object-Oriented Programming

When some part of the global data needs to be changed:

to improve performance

or to add new capabilities,

a large number of functions may be affected

and hope everything still works!

– you will have to rewrite them –

6

People that were investigating the Software Engineering (and the related issue of optimizing the productivity in teams) observed that most often functions were working on related data

So came the concept of: Objects where not only the individual data-instantiation is done, but through which also

the functions are accessed and used!!! Hence, we no longer have a separation between the objects and the functions that

operate on them (encapsulation)

Objects to the Rescue

7

Objects to the Rescue

Figure out which functions go with which data.

8

Objects to the Rescue

Create an object for each set of data.

9

Objects to the Rescue

Create another object for another set.

10

Objects to the Rescue

And now, a third object.

11

Objects to the Rescue

12

Objects to the Rescue – no global(s)…

From now on, we’ll have only objects. 13

Now, the data members from one (Type Of) object are completely different; independent; AND hidden from the other (Types Of) objects…

Hence, whenever we want to change the way that a group of objects have been

implemented, a smaller number of functions need to be changed: the ones being member-functions of the class to which those objects belong…

Ergo: the program evolution becomes easier to manage!!!

Encapsulation

14

Comparative Example (from last time)

�  Consider the 2 sets of variables: ¡  best_name, best_price, best_score, and ¡  next_name, next_price, next_score

�  Each describes a product �  Common concept �  Hence, they deserve to be “grouped” in the code, in a

manner that would reflect the “grouped” in their semantics…

�  AND: once a particular behavior-aspect has been identified, code it so that each “product-object” knows how to behave…

15

the Interface

16

INTERFACE

Classes and Instances

17

You create the Car class and the individual objects are the concrete instances of that class… Class: describes the common properties of all its objects-instances, via the data members of that class!!!

Implements the member functions to specify the behavior available for each individual object.

=> At minimum, the cash register design needs member functions to do the following:

• Clear the cash register to start a new sale. • Add the price of an item. • Get the total amount owed and the count of items purchased.

Designing the Class – CashRegister Example

18

These activities will be our public interface. The public interface is specified by the member functions in

the class definition. The data members are defined in the class definition too.

Classes – Register Example:

19

Typically, we have the following “template”: class NameOfClass { public: // the public interface private: // the data members };

Any part of the program should be able to call the member functions – so they are in the public section.

Data members are defined in the private section of the class. Only member functions of the class itself can access them.

They are hidden from the rest of the program.

Classes – Register Example

class NameOfClass { public: // the public interface private: // the data members };

20

Here is the C++ syntax for the CashRegister class definition:

Classes – Register Example

class CashRegister { public: void clear(); void add_item(double price); double get_total() const; int get_count() const; private: // data members will go here };

21

There are two typical kinds of member functions: •  Mutators

•  Accessors

Member Functions (AKA Methods)

22

A mutator is a function that modifies the data members of the object.

class CashRegister { public: void clear(); void add_item(double price); double get_total() const; int get_count() const; private: // data members will go here };

2 mutators in the CashRegister class…

How do we call/invoke the member functions: 1. first, we create a variable of the type CashRegister 2. Then, we use the “.” (dot) notation:

Because these are mutators, whatever data was stored in that particular instance (register1), will be changed.

Mutators

CashRegister register1; ... register1.clear(); ... register1.add_item(1.95);

23

Mutators

24

An accessor is a function that queries a data member of the object. It returns the value of a data member to its caller.

Accessors

25

class CashRegister { public: void clear(); void add_item(double price); double get_total() const; int get_count() const; private: // data members will go here };

2 accessor functions for the CashRegister class (i.e., for its instances)

NOTE: accessors shouldNOT change the data in a particular object (only query it) – const

Example - to print the current total of the register1 object:

Accessors and Mutators – roles

cout << register1.get_total() << endl;

26

Hence, the role of these functions in the interface:

Class Definition Syntax

27

Data Members

class CashRegister { public: // interface private: int item_count; double total_price; };

28

Each CashRegister object must store the total price and item count of the sale that is currently rung up.

Encapsulation – Data Members

NOTE: every individual instance, i.e., CashRegister object has a separate copy of each of these data members. CashRegister register1; // NOTE: none is initialized, yet… CashRegister register2; … // After a few “mutators” calls, we have:

29

Encapsulation

int main() { ... cout << register1.item_count; // Error—use get_count() instead ... }

Because the data members are private, this won’t compile:

30

Not even “main” has the right to access any private data member…

NOTE: strictly speaking, nothing prevents a class designer from declaring data members as “public” – HOWEVER, that’s a BAD practice (contradicts the encapsulation-quest)!!!

NOTE++: there’s another access-privilege called protected

Encapsulation and Methods as Guarantees

We can write the mutator for item_count so that item_count can’t be set to a negative value.

If item_count were pubic, it could be directly set to a negative value by some misguided (or worse, devious) programmer.

31

Another benefit (evolution): You want to be able to make your classes more efficient or more capable, without affecting the programmers that use your classes.

The benefit of encapsulation is:

As long as those programmers do not depend on the implementation details, you are free to change them

at any time.

The Interface

A driver switching to an electric car does not need to relearn how to drive.

32

The interface should not change even if the details of how they are implemented change.

Now we have what the interface does, and what the data members are,

The next logical step is: How do we implement the member

functions???

Implementing the Member Functions

The add_item member function:

void add_item(double price) { item_count++; total_price = total_price + price; }

33

HOWEVER: this is NOT the add_item member function. This is indeed a function, just like we used to write, but

it has no connection with the CashRegister class

Implementing the Member Functions

To specify that a function is a member function of your class you must write

CashRegister:: in front of the member function’s name:

void CashRegister::add_item(double price) { item_count++; total_price = total_price + price; }

34

Implementing the Member Functions

Use CashRegister:: only when defining the function (in .cpp) – not in the class definition (in .h)

class CashRegister { public: ... private: ... };

void CashRegister::add_item(double price) { item_count++; total_price = total_price + price; }

Not here

Only here

35

Implicit Parameters

But, WHERE IS THE VARIABLE (for the data member that we’re changing)??? When a member function is called: The variable to the left of the dot operator is

implicitly passed to the member function. In the example, register1 is the implicit parameter.

CashRegister register1; ... register1.add_item(1.95);

36

Implicit Parameters

register1.add_item(1.95); void CashRegister::add_item(double price) { implicit parameter.item_count++; implicit parameter.total_price = implicit parameter.total_price + price; }

37

Calling a Member Function from another Member Function (of the SAME CLASS!)

Example: have a member function that adds multiple counts of the same item.

38

Calling a Member Function from a Member Function

We have already written the add_item member function and

the same good design principle of code reuse with functions

is still fresh in our minds, so:

void CashRegister::add_items(int qnt, double prc) { for (int i = 1; i <= qnt; i++) { add_item(prc); } }

39

Calling a Member Function from a Member Function

When one member function calls another member function on the same object, you do not use the dot notation.

Recall: implicit parameter ! register1.add_items(12,5.00);

void CashRegister::add_items(int qnt, double prc) { for (int i = 1; i <= qnt; i++) { implicit parameter.add_item(prc); } }

40

Calling a Member Function from a Member Function

41

const Correctness This will compile with no errors.

class CashRegister { void display(); // Bad style—no const ... };

42

However, some other, well intentioned, good design-thinking programmer may want to use your class, and actually create an array your register-objects, in some of his functions.

Very correctly they make the array const. void display_all(const CashRegister[] registers, int NREGISTERS)

{ for (int i = 0; i < NREGISTERS; i++) { registers[i].display(); } }

const Correctness

The compiler (correctly) notices that registrs[i].display() is calling a NON-CONST display method

on a CONST CashRegister object.

void display_all(const CashRegister[] registers, int NREGISTERS) { for (int i = 0; i < NREGISTERS; i++) { registers[i].display(); } }

compiler error

43

Special Member Functions: Constructors

A friendly construction worker

House house1; House house2; House house3; ...

44

Constructors

Definition: A constructor is a member function that initializes the data members of an object.

45

The (default) constructor is automatically called whenever an object is created.

CashRegister register1;

By supplying a constructor, you can ensure that all data members are properly set

before any member functions act on an object.

Constructors – why?

To understand the importance of constructors, consider the following statements:

CashRegister register1; register1.add_item(1.95); int count = get_count(); // What is the count?

46

Constructors – how?

You declare constructors in the class definition:

class CashRegister { public: CashRegister(); // A constructor ... };

47

Constructors

The name of a constructor is identical

to the name of its class: class CashRegister

{ public: CashRegister(); // A constructor ... };

48

Constructors are written to guarantee that an object is always fully and correctly initialized when it is defined.

NOTE: absolutely NO RETURN TYPE!!! (not even void!!!)

Constructors

Of course, the constructor must be defined...

CashRegister::CashRegister() { item_count = 0; total_price = 0; }

49

To connect the definition with the class, must use the same :: notation (scope resolution operator)

NOTE: a constructor without any parameters:

CashRegister::CashRegister() is called a default-constructor…

Constructors

Default constructors are called when you define an object and do not specify any parameters for the construction.

Notice that you do NOT use an empty set of parentheses.

CashRegister register1;

50

register1.item_count and register1.total_price are set to zero as they should

be, simply with:

CashRegister register1;

Constructors

Constructors can have parameters, and constructors can be overloaded:

class BankAccount { public: // Sets balance to 0 BankAccount(); // Sets balance to initial_balance BankAccount(double initial_balance); // Member functions omitted private: double balance; };

51

When you construct an object, the compiler chooses the constructor that matches the parameters that you supply

BankAccount joes_account; // Uses default constructor BankAccount lisas_account(499.95); // Uses BankAccount(double) constructor

Constructors

Data members of classes that have constructors will not be garbage.

For example, the string class has a default constructor that sets strings to the empty string ("").

52

... private: string name; double hourlyRate; };

CashRegister register1; ... register1.CashRegister(); // Error

NOTE: canNOT use constructors to Reset an existing instance… (use mutators!!!)

Constructors – The System Default Constructor

If you write no constructors at all, the compiler automatically generates

a system default constructor that initializes all data members of

class type with their “defaults” (which is just garbage for numeric and pointer data members).

53

Discovering Classes

One simple approach for discovering classes and member functions is to look for

the nouns and verbs in the problem description.

54

Often times,

•  nouns correspond to classes, and

•  verbs correspond to member functions.

Discovering Classes

Many classes are abstractions of real-life entities. •  BankAccount •  CashRegister

55

Generally, concepts from the problem domain (science, business, or a game) make good classes.

The name for such a class should be

a noun that describes the concept. Example: frequently used classes represent

system services such as files or menus.

Not Discovering Classes

What might not be a good class?

If you can’t tell from the class name what an object of the class is supposed to do, then you are probably not on the right track.

56

Example: try to write a class class PayCheckProgram {… };

Q: -- what is it that a particular object of this class would have to do??? Probably everything one can think of… Not a good idea. Try: Class PayCheck…

Not Discovering Classes

Another common mistake, made particularly by those who are used to writing programs that consist of functions, is to turn an action into a class.

57

For example, if you are to compute a paycheck, you might consider writing a.

class ComputePaycheck.

But can you visualize a “ComputePaycheck” object?

HAS-A

When you analyze a problem description, you often find that you have multiple classes.

It is then helpful to consider how these classes are related. One of the fundamental relationships between classes

is the “aggregation” relationship (which is informally known as the “has-a” relationship).

58

The aggregation relationship states that objects of one class contain objects of another class.

Discovering Classes

In summary, when you analyze a problem description,

you will want to carry out these tasks: • Find the concepts that you need to implement as classes.

Often, these will be nouns in the problem description. • Find the responsibilities of the classes.

Often, these will be verbs in the problem description. • Find relationships between the classes that you have discovered.

59

Separate Compilation: The Cash Register Program

#ifndef CASHREGISTER_H #define CASHREGISTER_H /** A simulated cash register that tracks the item count and the total amount due. */ class CashRegister

This is the header file, cashregister.h Notice the first two lines. There is an ending #endif at the end of the file. This makes sure the header is only included once. Always write these. Use the name of the class as shown.

60

Separate Compilation: The Cash Register Program

private: int item_count; double total_price; }; #endif

You include this header file whenever the definition

of the CashRegister class is required. Since this file is not a standard header file, you must enclose its name in quotes, not <...>, when you include it, like this:

#include "cashregister.h”

61

Separate Compilation: The Cash Register Program

#include "cashregister.h" CashRegister::CashRegister() { clear(); } void CashRegister::clear() { item_count = 0; total_price = 0; }

Notice that the implementation file ALWAYS #includes its own header file.

62

Separate Compilation

Note: the member functions comments are in the header file,

not the .cpp file. After all, they are part of the interface (so whoever needs to use them sees what

they’re all about…) not the implementation.

63