- •Table of Contents
- •Introduction
- •What Is C++?
- •Conventions Used in This Book
- •How This Book Is Organized
- •Part I: Introduction to C++ Programming
- •Part III: Introduction to Classes
- •Part IV: Inheritance
- •Part V: Optional Features
- •Part VI: The Part of Tens
- •Icons Used in This Book
- •Where to Go from Here
- •Grasping C++ Concepts
- •How do I program?
- •Installing Dev-C++
- •Setting the options
- •Creating Your First C++ Program
- •Entering the C++ code
- •Building your program
- •Executing Your Program
- •Dev-C++ is not Windows
- •Dev-C++ help
- •Reviewing the Annotated Program
- •Examining the framework for all C++ programs
- •Clarifying source code with comments
- •Basing programs on C++ statements
- •Writing declarations
- •Generating output
- •Calculating Expressions
- •Storing the results of expression
- •Declaring Variables
- •Declaring Different Types of Variables
- •Reviewing the limitations of integers in C++
- •Solving the truncation problem
- •Looking at the limits of floating-point numbers
- •Declaring Variable Types
- •Types of constants
- •Special characters
- •Are These Calculations Really Logical?
- •Mixed Mode Expressions
- •Performing Simple Binary Arithmetic
- •Decomposing Expressions
- •Determining the Order of Operations
- •Performing Unary Operations
- •Using Assignment Operators
- •Why Mess with Logical Operations?
- •Using the Simple Logical Operators
- •Storing logical values
- •Using logical int variables
- •Be careful performing logical operations on floating-point variables
- •Expressing Binary Numbers
- •The decimal number system
- •Other number systems
- •The binary number system
- •Performing Bitwise Logical Operations
- •The single bit operators
- •Using the bitwise operators
- •A simple test
- •Do something logical with logical calculations
- •Controlling Program Flow with the Branch Commands
- •Executing Loops in a Program
- •Looping while a condition is true
- •Using the for loop
- •Avoiding the dreaded infinite loop
- •Applying special loop controls
- •Nesting Control Commands
- •Switching to a Different Subject?
- •Writing and Using a Function
- •Divide and conquer
- •Understanding the Details of Functions
- •Understanding simple functions
- •Understanding functions with arguments
- •Overloading Function Names
- •Defining Function Prototypes
- •Variable Storage Types
- •Including Include Files
- •Considering the Need for Arrays
- •Using an array
- •Initializing an array
- •Accessing too far into an array
- •Using arrays
- •Defining and using arrays of arrays
- •Using Arrays of Characters
- •Creating an array of characters
- •Creating a string of characters
- •Manipulating Strings with Character
- •String-ing Along Variables
- •Variable Size
- •Address Operators
- •Using Pointer Variables
- •Comparing pointers and houses
- •Using different types of pointers
- •Passing Pointers to Functions
- •Passing by value
- •Passing pointer values
- •Passing by reference
- •Limiting scope
- •Examining the scope problem
- •Providing a solution using the heap
- •Defining Operations on Pointer Variables
- •Re-examining arrays in light of pointer variables
- •Applying operators to the address of an array
- •Expanding pointer operations to a string
- •Justifying pointer-based string manipulation
- •Applying operators to pointer types other than char
- •Contrasting a pointer with an array
- •Declaring and Using Arrays of Pointers
- •Utilizing arrays of character strings
- •Identifying Types of Errors
- •Choosing the WRITE Technique for the Problem
- •Catching bug #1
- •Catching bug #2
- •Calling for the Debugger
- •Defining the debugger
- •Finding commonalities among us
- •Running a test program
- •Single-stepping through a program
- •Abstracting Microwave Ovens
- •Preparing functional nachos
- •Preparing object-oriented nachos
- •Classifying Microwave Ovens
- •Why Classify?
- •Introducing the Class
- •The Format of a Class
- •Accessing the Members of a Class
- •Activating Our Objects
- •Simulating real-world objects
- •Why bother with member functions?
- •Adding a Member Function
- •Creating a member function
- •Naming class members
- •Calling a Member Function
- •Accessing a member function
- •Accessing other members from a member function
- •Defining a Member Function in the Class
- •Keeping a Member Function After Class
- •Overloading Member Functions
- •Defining Arrays of and Pointers to Simple Things
- •Declaring Arrays of Objects
- •Declaring Pointers to Objects
- •Dereferencing an object pointer
- •Pointing toward arrow pointers
- •Passing Objects to Functions
- •Calling a function with an object value
- •Calling a function with an object pointer
- •Calling a function by using the reference operator
- •Returning to the Heap
- •Comparing Pointers to References
- •Linking Up with Linked Lists
- •Performing other operations on a linked list
- •Hooking up with a LinkedListData program
- •A Ray of Hope: A List of Containers Linked to the C++ Library
- •Protecting Members
- •Why you need protected members
- •Discovering how protected members work
- •Protecting the internal state of the class
- •Using a class with a limited interface
- •Creating Objects
- •Using Constructors
- •Why you need constructors
- •Making constructors work
- •Dissecting a Destructor
- •Why you need the destructor
- •Working with destructors
- •Outfitting Constructors with Arguments
- •Justifying constructors
- •Using a constructor
- •Defaulting Default Constructors
- •Constructing Class Members
- •Constructing a complex data member
- •Constructing a constant data member
- •Constructing the Order of Construction
- •Local objects construct in order
- •Static objects construct only once
- •Global objects construct in no particular order
- •Members construct in the order in which they are declared
- •Destructors destruct in the reverse order of the constructors
- •Copying an Object
- •Why you need the copy constructor
- •Using the copy constructor
- •The Automatic Copy Constructor
- •Creating Shallow Copies versus Deep Copies
- •Avoiding temporaries, permanently
- •Defining a Static Member
- •Why you need static members
- •Using static members
- •Referencing static data members
- •Uses for static data members
- •Declaring Static Member Functions
- •What Is This About, Anyway?
- •Do I Need My Inheritance?
- •How Does a Class Inherit?
- •Using a subclass
- •Constructing a subclass
- •Destructing a subclass
- •Having a HAS_A Relationship
- •Why You Need Polymorphism
- •How Polymorphism Works
- •When Is a Virtual Function Not?
- •Considering Virtual Considerations
- •Factoring
- •Implementing Abstract Classes
- •Describing the abstract class concept
- •Making an honest class out of an abstract class
- •Passing abstract classes
- •Factoring C++ Source Code
- •Defining a namespace
- •Implementing Student
- •Implementing an application
- •Project file
- •Creating a project file under Dev-C++
- •Comparing Operators with Functions
- •Inserting a New Operator
- •Overloading the Assignment Operator
- •Protecting the Escape Hatch
- •How Stream I/O Works
- •The fstream Subclasses
- •Reading Directly from a Stream
- •Using the strstream Subclasses
- •Manipulating Manipulators
- •Justifying a New Error Mechanism?
- •Examining the Exception Mechanism
- •What Kinds of Things Can I Throw?
- •Adding Virtual Inheritance
- •Voicing a Contrary Opinion
- •Generalizing a Function into a Template
- •Template Classes
- •Do I Really Need Template Classes?
- •Tips for Using Templates
- •The string Container
- •The list Containers
- •Iterators
- •Using Maps
- •Enabling All Warnings and Error Messages
- •Insisting on Clean Compiles
- •Limiting the Visibility
- •Avoid Overloading Operators
- •Heap Handling
- •Using Exceptions to Handle Errors
- •Avoiding Multiple Inheritance
- •Customize Editor Settings to Your Taste
- •Highlight Matching Braces/Parentheses
- •Enable Exception Handling
- •Include Debugging Information (Sometimes)
- •Create a Project File
- •Customize the Help Menu
- •Reset Breakpoints after Editing the File
- •Avoid Illegal Filenames
- •Include #include Files in Your Project
- •Executing the Profiler
- •System Requirements
- •Using the CD with Microsoft Windows
- •Using the CD with Linux
- •Development tools
- •Program source code
- •Index
296 Part IV: Inheritance
namespace Schools
{
char* GraduateStudent::display()
{
//get description of basic student char* pFirst = Student::display();
//we’ll add this text
char* pSecond = “-G”;
// get a new string and tack second onto first char* pName = new char[strlen(pFirst) +
strlen(pSecond) + 1];
strcpy(pName, pFirst); strcat(pName, pSecond);
//don’t forget to return the string returned by
//Student::display() to the heap before passing
//our new string to the caller
delete pFirst; return pName;
}
}
The GraduateStudent version of display() concatenates a “-G” onto the end of whatever Student returns. It begins by allocating a new character array that’s large enough to handle the extra information.
Never assume that there’s enough room in the original buffer for any extra characters to be tacked onto the end.
The program copies the contents of the original string into the newly allo cated array. It then appends the “- G”. The display() function must return the buffer allocated by Student::display() to the heap before continuing.
Forgetting to return buffers to the heap is known as a memory leak. A pro gram with memory leaks executes properly at first; however, the program slows more and more as the available memory is lost to the leaks. The pro gram eventually grinds to a halt. Memory leaks are very difficult to find.
Implementing an application
The two classes, Student and GraduateStudent, have been separated into independent source files and included in the Schools namespace. I wrote the following very simple application to invoke the two classes:
Chapter 22: Factoring Classes 297
// SeparatedMain - demonstrated an application separated // into two parts - the main() part #include <cstdio>
#include <cstdlib> #include <iostream>
#include “graduateStudent.h” #include “student.h”
using namespace std; //using namespace Schools;
using Schools::GraduateStudent;
int main(int nArgc, char* pszArgs[])
{
Schools::Student s(“Sophie Moore”, 1234); cout << “Student = “ << s.display() << endl;
GraduateStudent gs(“Greg U. Waite”, 5678); cout << “Student = “ << gs.display() << endl;
//wait until user is ready before terminating program
//to allow the user to see the program results system(“PAUSE”);
return 0;
}
The application includes both the student.h and graduateStudent.h include files. This gives the application access to the definition of the two classes.
You might notice that including graduatestudent.h automatically includes student.h. However, you shouldn’t take it for granted; include student.h if you access the Student class directly, whether or not you include graduateStudent.h. The #ifndef, which you installed in student.h, will make sure that the contents of student.h are not processed twice by the C++ compiler.
SeparatedMain is not a member of the Schools namespace. When main() refers to the Student class, C++ does not know whether the programmer intends to use the Student found in the Schools namespace or a similarly named class in some other namespace.
main() can completely specify a class without any possibility of ambiguity because Schools::Student refers specifically to the namespace and class. Alternatively, the programmer can specify her intentions at the beginning of the module: The phrase using Schools::GraduateStudent; tells C++ that any mention to GraduateStudent refers to the Schools namespace.
298 Part IV: Inheritance
The programmer can gain access to all members of the Schools namespace by adding the command using namespace Schools. The following version of main() builds successfully:
using namespace Schools;
int main(int nArgc, char* pszArgs[])
{
Student s(“Sophie Moore”, 1234);
cout << “Student = “ << s.display() << endl;
GraduateStudent gs(“Greg U. Waite”, 5678); cout << “Student = “ << gs.display() << endl;
//wait until user is ready before terminating program
//to allow the user to see the program results system(“PAUSE”);
return 0;
}
You began using the using namespace std statement at the beginning of the book. The modules that make up the Standard C++ Library are members of the std namespace.
Project file
Full of expectation, I open the SeparatedMain.cpp file in the compiler and click Build. The module compiles properly, but an error occurs during the linking process. C++ does not know what a Student is. Somehow you have to tell C++ that the Student.cpp and GraduateStudent.cpp files need to be linked together with SeparatedMain.cpp to create the program. Most C++ environments, including both Dev-C++ and Visual C++.NET, combine multiple modules together via a project file.
Dev-C++ and Visual C++ use their own project file formats. The directions for creating a C++ console application project within Visual Studio.NET is pro vided on the enclosed CD-ROM in Bonus Chapter 2.
Creating a project file under Dev-C++
Execute the following steps to create a Dev-C++ project:
1.Choose File New Project. Select Console Application and type the name SeparateModules.
You should see the window in Figure 22-6.
Chapter 22: Factoring Classes 299
Figure 22-6:
The New Project window allows the user to enter the name and type of project.
2.Click OK.
Dev-C++ opens a file window.
3.Select the directory into which to store the project.
I selected \CPP_Programs\Chap22. Dev-C++ creates a project with a default initial module main.cpp.
4.Remove main.cpp from the project because you already have a main() module.
5.Choose Project Remove From Project.
6.Select main.cpp and click OK.
7.Copy the files main.cpp, Student.cpp, GraduateStudent.cpp, student.h, and graduateStudent.h to the Chap22 folder if they aren’t there already.
8.Choose Project Add to Project.
9.Select the entire list of source modules and click OK.
10.Choose Execute Rebuild All to compile the modules in the project and create an executable program.
11.Click the Classes tab in the left window to see a detailed description
of each class in the program, as shown in Figure 22-7.
Make sure that the class browser is enabled and configured properly.
300 Part IV: Inheritance
Figure 22-7:
The classes tab displays the members of each class.
Figure 22-8:
The class browser options tab determines the type of information available in the class browser.
12.Choose Tools Editor options and click the Class browsing tab.
13.Click the Enable Class Browser browser and the options shown in Figure 22-8.
Notice how the class browser displays each member. Functions display with their argument types as well as the type of object returned. Notice also that the class browser shows two display() member functions under the GraduateStudent class.
Chapter 22: Factoring Classes 301
14.Select the first display() entry in the list, the one with the small dia mond in front of it.
This opens the Student.cpp file and places the cursor on the display() member function. Selecting the second display() entry in the class browser takes the editor to the GraduateStudent::display() member function.
The properties of the project are initially set to the default. You can change the settings as follows.
15.Select Project Project Options.
For example, select the Linker options under the Compiler tab. Now make sure that Generate Debugging Information is set to Yes if you intend to use the Dev-C++ debugger.
I encourage you to break your programs into multiple source files. It simpli fies the editing, modifying, and debugging process.
302 Part IV: Inheritance
Part V
Optional Features
In this part . . .
The goal of this book is not to turn you into a C++ lan guage lawyer; it’s to give you a solid understanding of
the fundamentals of C++ and object-oriented programming.
The earlier parts in this book cover the essential features you need to know to produce a well-written, object-oriented C++ program. C++, however, is a big language (it has a seri ous case of feature-itis, if you ask me), and I have yet to discuss many features such as file input/output and the Standard Template Library. Part V rights this wrong.
C++ programmers have increasingly come to exploit the features of this library in the past few years. The BUDGET4 and BUDGET5 programs on the enclosed CD-ROM demon strate how.