C++ Class Part 2

From EDM2
Jump to: navigation, search
C++ Class / Part
1 2 3 4 5 6

By Terry Norton

We now start getting to more complicated material. Building on what we learned in Chapter 3, data types, we now learn how to create far more powerful types for use in program control. We also begin learning about Pointers which help use the full power of C++.

Chapter 4 Compound Types

After reading Chapter 4, you should understand the following concepts:

  • Arrays, enumeration, structures, unions, and pointers
  • Dynamic memory and why it is used
  • Basic management of dynamic memory with new and delete
  • String input and output using basic istream and ostream classes and member functions
  • Null terminated strings verus arrays of characters
  • Enumeration variables and ranges of values
  • Type of memory use in C++ and its scope
  • Referencing members of static and dynamic structures

Static Arrays

Arrays provide the C++ programmer with flexibility in working with data. This section introduces concepts of data management. The full benefit of arrays will be realized when we later learn about loops. As you read, here are the array main points:

  • Used for multiple values of the same data type
  • Creating an array
  • Derived types: based on other types
  • Access to array members
  • sizeof returns number of bytes in an array
  • Initializing arrays

An array is very simple. So far you are used to creating a single variable, such as int money. If you wanted more, you might make more variables, like money1, money2, money3, etc. However, the array lets you make a bunch of variables in one shot. So you could do int money[4] instead, which makes 4 money variables. So now to get the value, or data, stored in the second money variable you would do a cout << money[1];. NOTE: Do not use <cstring> with OpenWatcom, no such file. Use <string> or <string.h>

Strings

Strings is a further case in the use of arrays. The main points for strings:

  • A special form of array
  • Series of characters stored in consecutive bytes of memory
  • Null terminated string verus an array of char
  • Using quoted strings to initialize, which automatically includes the null terminator
  • Concatenation of strings separated only by whitespace
  • String input; using cin member functions getline() and get()

Line-Oriented Input: getline() and get()

Strings in arrays are simple enough, one character in each element of an array, and at the end the null character "\0". getline() and get() are Class member functions. They write this in the book like it's a back page item, but C++ is about Classes, and I want to point this out at every opportunity. The Class, istream (defined in the file iostream), has functions in it. getline() and get() are two of them. They are called members functions because they are part of the istream Class. To use these member functions, an object of the istream Class, cin, has to be a sent message to use them. cin.getline(name, ArSize) in Listing 4.4 does this. All this will really become apparent when we start creating our own Classes and defining member functions in them.

On page 108 you find the word concatenate. You will see this a lot in programming, so burn it into your memory. It just means join, but they have to be fancy.

Introducing Structures

Structures are the first hint of how Classes are created. Structures can hold different types of data, such as int, float, char, etc., all at the same time, as opposed to arrays which can only hold one type of data in its elements.

The main points for the C++ Structure:

  • It's a derived data type that contains various data items related to an object
  • An array of structures to contain data about several related objects
  • Creating a structure - define a structure description - create a structure data object (variable)
  • Referencing structure members

The structure is a user-defined type. You create it and name it. Just like an int or a char is a type already supplied for your use, when you make a structure you are creating a type to suite your purposes, then using it just like any of the other fundamental types that C++ already supplies.

Listing 4.7 is starting to get into some good stuff here. Even though these are Structure objects and not Class objects, the method used to access the data stored in the structure objects show how simple it is to get data from an object, such as pal.name in the example.

On page 116, they're showing a structure type declaration. It may look complicated, but it's just as simple and declaring any other data type. I'll show something you're familiar with:

int cost, change; 

Here I've created two variables of type int. The structure type variables are being created the same way on page 116, but with a little more structure info:

struct perks { int key_number; char car[12]; } mr_smith, ms_jones; 

I've put the declaration all on one line to show the comparison between the two declarations. Here we have created a structure called perks. perks is now a type, as int is a type. In the brackets is the declarations for what's in a perks type, an int and a char Right after the "}/" is the names of the variables created, mr_smith and ms_jones, just like cost and change were variables we created. Both these variables are of the perks type, just like cost and change are variables of the int type. perks just happens to be a structure, whereas int is an integer. If you have questions, please ask.

A little tidbit of info in the few sentences at the top of page 117. C++ structures can have member functions as well as member variables. C can only have member variables. What you will see in C++ is that a Class is basically a C++ structure.

Enumerations

This is a user-defined type. An enum variable can only be assigned a value that the user has specified when the enum was defined. In other words, when you define an enumeration, you have created some constants. Only the constants, or the value that you assigned to the constants, can be assigned to a enumeration variable, if you infact ever create an enum variable. You may just decide to use the constants directly in your program. For example, you can give the days of the week a constant value:

enum {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}; 

Sunday is 0, Monday is 1, etc. Any time you use Sunday the value 0 is substituted in your program:

int today = Sunday;  

The variable today how has the value 0. The alternative to defining with an enum is like this:

const int Sunday = 0; 
const int Monday = 1; 
const int Tuesday = 2; 
 ...  

This is much more awkward than just using an enum. If you do define an actual enum variable, then the variable can only have a value that has been defined in the enum:

enum day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}; 

The type day can now be used to define a variable:

day today = Sunday;  

The variable today can only be assigned one of the constants defined in the day enumeration.

Pointers and the Free Store

We are now going to get into a subject that may appear difficult, simply because it causes you to think from a different point of view. Let's do this, you have a quarter in your hand with the heads side showing. You can look at it and tell it's a quarter. However, if you turn it over so the tails side shows, can you still tell it's a quarter? Of course you can because you've already learned to view it from two different views. Variables can also be viewed from two different views.

So far you've learned, in the Twilight Zone, that a mailbox (memory address in my computer) can be given a name (variable name). I called my address Norton. So my mailbox has the variable name Norton on it. I didn't actually mention my address (the memory address) in Lesson one, but it is 10 (10 is my initials, Terry E. Norton). So the number on my box is 10, and the name on my box is Norton. The Twilight Zone mailman has learned that he can deliver mail to my house by knowing either my address, 10, or by the name on the box, Norton.

If you also recall, when my mailbox was opened, there was 54 on a piece of paper inside (my age). So to review, what we have here is a mailbox with the address 10, a name of Norton, and 54 in it (54 is an int in my mailbox). Simple, right? Anyone that wants to come to the Twilight Zone to find where I live can do it on this street by knowing my address or my name, and they can see what's in my mailbox (memory address).

You can easily get the value from the variable by:

cout << Norton; 

This will show 54 on my screen. The address of Norton is the memory address 10. So I can also get 54 if I want by looking at the memory address directly instead of using the name I gave it of Norton. Sound simple enough? Well, that's what we're going to do with a little item called a pointer. A pointer is a variable that contains, or points to, the memory address. Piece of cake, I just point to 10 and I can get the value 54.

What makes pointers appear so difficult is simply the way it looks on paper. For some reason, someone got the great idea to use the symbol "*" for pointers, which just happens to be the symbol for multiplication. So when you see it on paper mixed in with a bunch of words, it just doesn't want to sink in, it looks hard.

With pointers we are about to get into effective management in C++. The main topics in this section of the book are:

  • Ordinary variables: the value is the named quantity and the location as the derived quantity
  • Pointer variables: the location is the named quantity and the value is the derived quantity
  • Static binding and Dynamic binding
  • The address operator: &
  • Indirect value or dereferencing operator: *
  • Declaring and initializing pointers
  • Pointers and numbers

If you totally understand pointers as explained in the book, celebrate! I had to reread this stuff over several times until I could look at it and believe I understood it well enough to move on. I realize my little trip into the Twilight Zone is rather odd, but it has helped sink this material into my uncooperative gray matter. But it's still difficult seeing the dereferencing operator, *, splattered all over some code. I tend to go numb. Just bear with me a little more as I relate this to my Twilight Zone address.

int Norton ;        //creates a variable for the name on my mailbox
Norton = 54;        //assigns my age to my mailbox variable
cout << Norton;     //this displays my age 54

So far that's the easy part.

int * p_Norton;       //creates a pointer-to-int
p_Norton = &Norton;   //gets the address, 10, where my age is stored and assigns it to the pointer
cout << p_Norton;     //this displays 10 on my screen
cout << *p_Norton;    //this displays my age 54 

</tt> Therefore, Norton and *p_Norton are exactly the same.

Allocating Memory with new

The problem with starting a program is that there is just a limited amount of memory allocated to the stack and program memory. Ever hear of a stack overflow as a program crashes? A program should be able to use all that extra memory we all have in our computers now. All that extra, unused memory is called the heap, or free store. The heap can't have named variables, so to use the heap and know where info is stored, you need a pointer to get at the info. This is where the new operator is used, to use some of the heap while the program is running. This is where pointers come into play instead of named variables.

Remember, just above, I said Norton and *p_Norton are exactly the same? p_Norton is a pointer. It points to the memory location that contains the information, 54, that we seek. To get at the information, we take the pointer and dereference it by placing the dereferencing operator in front of the pointer like this, *p_Norton. Technically, you could say *p_Norton is the variable name for the heap memory, just like Norton is for the stack memory. Therefore,

nt * p_Norton = new int; >

creates a new memory location in heap memory to hold an int. p_Norton is the pointer (of type point-to-int) that holds the new memory location. *p_Norton holds the data, 54. Where Norton was the variable name in the stack, holding the data 54, we now have *p_Norton in the heap holding the data.

Using new to Create Dynamic Arrays

Reviewing a little about arrays,

int price[100];   //creates an array of 100 int variables </tt>

The price array is created on the stack, and is created at compile time whether you use it or not, static binding. The stack has limited memory, creating it on the heap is better. Create it with new when you need it, dynamic binding.

int * price = new int [100]; 

Now the array has been created on the heap, or free store, of memory, and price is a pointer to the first element of the array.

Now for a curve ball. You just learned about pointers and how to dereference a pointer to get the value. With arrays made with new you can't use the dereference operator "*" to get the value in an element. We are to treat the pointer name as the array name.

Just to see what would happen, I compiled arraynew.cpp (page 134) first to make sure it ran properly, it does. I then changed the source so that

 p3[0] = 0.2; 

looked like

 *p3[0] = 0.2; 

This won't compile, so do NOT use the dereference operator with arrays. The book goes on to explain why with the addpntrs.cpp example (page 135). At the top of page 139 the book says array notation is a second way to dereference a pointer.

Pointers and Strings

There are a lot of examples in the book covering strings. The main point to remember is that a string assigned to a pointer behaves like regular arrays do, with one difference. When you pass a string pointer to cout, cout continues to print out the contents of memory until it reaches a null character '\0'.

Using new to Create Dynamic Structures

NOTE: The example newstrct.cpp needs to have:

delete ps;

added before the return statement.

Using pointers with structures requires a slightly modified operator to access the data stored in a structure. This is the main point for this section of the book. With a named structure, use the "." (period) operator, with a pointer to a structure, use the "->" operator.

This has been a fairly long chapter covering quite a few items. The main item has been pointers and how they work, and how to use them. Pointers could be the most difficult material to master. For those of you coming from REXX, like me (even if only a short time), thinking backward to get data through pointers has been the most difficult to visualize. For total programming newbies, you probably will have an easier time since you aren't dragging old programming ideas along.

Questions for Chapter 4

True or False

  1. An array can contain any combination of data types.
  2. char animal[ ] = {"horse", \0} is a valid initialization of a string array.
  3. An array of char is a string only if a null terminator is the last character.
  4. cin stops accepting input to the current variable when \0 is received from the keyboard.
  5. If memory is exhausted, int* stuff = new int; will return a null pointer.