Topic: C# and C++

Beginning Visual C++ 6 (0764543881) cover image

Beginning Visual C++ 6

Ivor Horton
ISBN: 978-0-7645-4388-3
1224 pages
August 1998
This title is out-of-print and not currently available for purchase from this site.

Do you think you've discovered an error in this book? Please check the list of errata below to see if we've already addressed the error. If not, please submit the error via our Errata Form. We will attempt to verify your error; if you're right, we will post a correction below.

ChapterPageDetailsDatePrint Run
21 Page 21: TrialRun.cpp
A line is missing from the TrialRun.cpp program shown on page 21. The listing should be as follows:
// TrialRun.cpp
// Our first program
#include <iostream>

using namespace std;

int main()
   // code as shown in book

The missing line is shown in the screenshot on the following page and is used throughout the rest of the book. 'using namespace std;' allows routines from the C++ standard library to be incorporated into the program (in this case 'cout'). The using directive and namespaces are explained on pages 42 and 85 to 88.

17-Sep-98 1
83 Page 83: Try It Out - The Scope Resolution Operator

The second sentence of the paragraph introducing the 'Try It Out' concludes with an erroneous statement. The sentence should simply read as follows:

However, it's still possible to get at the global variable using the scope resolution operator (::).

Namespaces are discussed in Chapter 2, not Chapter 1. The scope resolution operator is not discussed until Chapter 8.

13-Jul-99 1
85 Page 85: Namespaces

The second sentence on page 85 should read as follows:

We'll talk further about namespaces, including how to create your own, shortly.

14-Jul-99 1
86 Page 86: Demonstrating Namespace Names

In exercise 2_08.cpp, the line,

std::cin << value;

should read as follows:

std::cin >> value;

28-Sep-98 1
88 Page 88 typo

The third sentence on the page should read as follows:

Of course, you would not usually organize a source file in this way deliberately, but it can arise quite naturally with header files that you include into a program.

Thanks to Ryan McLaughlin

18-May-01 1
137 Clarification on use of cin.getline()

Some readers have asked for clarification regarding the use and behavior of cin.getline() as it compares to using the << operator. In particular, a problem can arise when the former is used immediately after the latter.

These two techniques of obtaining input differ in the way they deal with the carriage return that typically terminates text entered by the user. Specifically, << doesn't remove the carriage return from the input stream, but cin.getline() does. A potential consequence of this is that when cin.getline() is called after using <<, it finds the carriage return that's been left in the input buffer and returns immediately, offering the user no opportunity to provide the input you were seeking.

If you need to use cin.getline() after using <<, one option available to you is to call cin.ignore() before doing so, as this will remove the stray carriage return from the input buffer.

05-Mar-03 1
145 Page 145: Hexadecimal Numbers

In Visual C++ 6, unlike Visual C++ 5, hexadecimal numbers are not prefixed by 0x when they appear on screen.

29-May-00 0
147 Page 147: Terminating a String

appearing between the quotes and terminated with /0
should read
appearing between the quotes and terminated with \0

29-May-00 1
178 Page 178: Missing Bracket

At the bottom of the page, there should be an opening bracket ( between static_cast<int> and 2.0.

29-May-00 1
193 Missing line of code
The code listing on this page is missing a line that was present in the code on p191. The listing should begin:
#include <iostream>
#include <cstdlib>
using namespace std;
05-Nov-02 1
217 Misleading section on handling memory allocation errors

The section that occupies the majority of this and the following page is misleading. To use the _set_new_handler() function, it's necessary to include the new.h header file in your code, rather than the standard library file new that the book identifies. However, it's also possible to include new, and then to use the standard library function set_new_handler() (note the lack of a leading underscore) instead.

24-Feb-03 1
227 Page 227: Eliminating Blanks from a String

In the function eatspaces, the return statement is unnecssary.

Enclosing the lines
if(*(str+i) != ' ')
in curly brackets, i.e.
if(*(str+i) != ' ')
will make the code easier to understand, although this is not essential.
29-May-00 1
234 Page 234: Analyzing a Number

In the final line of the figure at the top of page 234, the factor should be 0.001 (not 0.01, as shown).

05-Jan-99 1
238 Page 238: Extracting a Substring

The penultimate line of the extract() function on page 238 is superfluous - the program will compile and run with or without it. The exit(1); command ends the program, thus rendering the return pstr; line that follows it redundant. (It removes any need to return from the function at this point.)

16-Feb-99 1
241 Page 241: Exercise 6-1

In the answer to Exercise 6-1, the variable P[i] in the final line of the function should be enclosed in brackets:

return static_cast<int>(p[i]);

05-Jan-99 1
272 Page 272: A Complete WindowProc() Function

The WINAPI specifier in both the WindowProc() function definition on page 272 and its prototype on page 273 should be replaced with CALLBACK, so that they read as follows:

long CALLBACK WindowProc(...)

04-Feb-99 1
308 Page 308: const keyword

The function header double volume() should be followed by the keyword const.

26-May-00 1
310 Page 310: Arrays of Class Objects
The constructor definition in Exercise 8_10 should read:
CBox(double lv, double bv = 1.0, double hv = 1.0): m_Length(lv), m_Breadth(bv), m_Height(hv)
   cout << endl << "Constructor called.";
The code shown in the book causes ambiguity over which constructor should be called, giving rise to the compiler errors described on page 295. In the code in the book, both constructors could be used to initialize the data members of the CBox objects in the array boxes. If a default value for lv is not supplied in the first constructor, the compiler knows it cannot use that constructor for the initialization and so uses the default constructor.
24-Sep-98 1
312 Page 312: Counting Instances
The constructor definition in Exercise 8_11 should read:
CBox(double lv, double bv = 1.0, double hv = 1.0): m_Length(lv), m_Breadth(bv), m_Height(hv)
   cout << endl << "Constructor called.";
The code shown in the book causes ambiguity over which constructor should be called. A more detailed explanation can be found in the erratum for page 310.
25-Sep-98 1
320 Page 320: Exercises 8-2 and 8-3

The model answers to Exercises 8-2 and 8-3 use destructors, which aren't covered until the next chapter.

05-Jan-99 1
330 Page 330: DisplayMessage() function definition
​​ If you try to incorporate the code snippets shown on page 330 into Exercise 09_02 the program will not compile. This is because the ShowIt() function is defined as having a void return type but the << operator cannot take a right hand operand of type void. The DisplayMessage() function should, therefore, be defined as follows:
void DisplayMessage(CMessage localMsg)
   cout << endl << "The message is: ";

Thanks to Sasa Bosnjak.
17-Sep-98 1
343 Page 343: comment
The second comment in the code at the bottom of the page should read //Check addresses. If equal, return a reference to the 1st operand.
12-Jun-00 1
343 Page 343: motto1
The line
Motto1 = *pMess;
should read
motto1 = *pMess;
where motto1 starts with a lower case 'm'.
29-May-00 1
347 Page 347: Overloading the Addition Operator

The second comment (// Class definition at global scope) wraps on to the next line. "scope" is not a command!

05-Jan-99 1
351 Page 351: Defining a Class Template
A semicolon is missing from the default constructor at the top of the page. The default constructor should read as follows:
  m_Free = 0;
Also, the comment on the penultimate line of the class listing wraps onto the next line. m_Values is not a command, it is part of the comment on the previous line, which should read as follows:
int m_Free;   // Index of free location in m_Values
04-Feb-99 1
363 Page 363: Analyzing CBox Objects

At the top of page 363, the return statement includes a static_cast with a bracket instead of an angled bracket. The line should read as follows:

return static_cast<int>(...code as shown in book...);

05-Jan-99 1
374 Page 374: Adding Global Functions

The second parameter of the CBox multiply operator should be a reference. The next-to-last line in the list of declarations for global box operators should read as follows:

CBox operator*(int n, const CBox& aBox);

05-Jan-99 1
374 Using Visual C++ Macros

When you follow the book's instructions for running macros, you may find yourself confronted by a blank Macro dialog box. Should this happen to you, there's a relatively easy fix.

With no files open in Visual C++6, you need to click on Tools | Macro. Then, in the Macro dialog box that appears, you have to click on Options | Loaded Files. Finally, in the Add-ins and Macro Files tab of the Customize dialog box that appears, you need to enable the Sample macro by clicking on the check box. After you've closed the dialog, you can follow the book's directions to run the macro.

05-Mar-03 1
380 Page 380: Summary

In the final line of the first bullet point, "default constructor" should read, "default destructor".

16-Feb-99 1
386 Page 386: Deriving Classes from a Base Class

The destructor in listing 10_01-02 should not have a semicolon after the closing curly bracket.

05-Jan-99 1
391 Page 391: Constructor Operation in a Derived Class

The first line of the first paragraph in the section entitled "Constructor Operation in a Derived Class" should read as follows:

Although we said that the base class constructor is not inherited in the derived class, it still exists for the base part of the derived class object.

05-Jan-99 1
404 Friend Classes
The fourth line on page 404 reads:

friend CCarton;

It should read as follows:

friend class CCarton;
21-Jun-00 1
420 Page 420: Calling the Wrong Destructor

In the paragraph below the screenshot, the third sentence should read as follows:

For the other objects, the correct destructor calls occur with the derived class destructor being called first, followed by the base class destructor.

23-Feb-99 1
443 Page 443: Making the CCalculator Class Safe to Use

Due to what appears to be a bug in the ClassWizard, using the Add Member Function dialog to add the assignment operator to the CCalculator class will not work. An implementation will be provided in the Calculator.cpp file but no declaration will be added to the class definition in Calculator.h.

Consequently you shouldn't bother with the Wizard and should add the declaration manually. The declaration should be placed in the private section of the class, as shown on page 445.

As stated in the book, no implementation is needed - if you've used the Wizard to add the assignment operator function you should delete the implementation that the Wizard produces.

02-Oct-98 1
444 Page 444: Starting the Calculator
The declaration of the copy constructor for the CCalculator class should be in the private section of the class (as stated in the text) and not in the public section (as shown in the class definition).

The correct class definition is shown below:
class CCalculator
    void Run() const;
    virtual ~CCalculator();
    CCalculator(const CCalculator& rCalculator);
    CCalculator& operator=(const CCalculator& rhs);
    CKeyboard* m_pKeyboard;
    CLogicUnit* m_pLogicUnit;
    CDisplay* m_pDisplay;
02-Oct-98 1
444 Page 444: implementation

In later editions, the sentence,
"If you have used ClassWizard to add the operator function, you will need to delete the implementation as it is added automatically",
is added to the first paragraph on the page.

13-Jun-00 1
450 Page 450: Declaration of CLogicUnit::OnDigit()

The function CLogicUnit::OnDigit() should be declared as:

void OnDigit(const int& digit);

This amendment to the function's parameter also applies to the declaration of OnDigit() shown on page 452 and its implementation shown on page 453.

05-Jan-99 1
451 Page 451: Logic Unit Registers Table

Some of the values shown in the table do not accurately reflect the workings of the code.
When the '+' is entered the values held in the registers should be as follows:
Display = 1.5
Multiply = 1.5
Add = 1.5

When '5' is entered the values should be:
Display = 5
Multiply = 1.5
Add = 1.5

When 'Enter' is pressed, the values should be:
Display = 6.5
Multiply = 1.5
Add = 6.5

Thanks to Sasa Bosnjak.

17-Sep-98 1
453 Page 453: OnDigit function

The OnDigit function should be declared as follows.
void OnDigit(const int& digit);

09-Jun-00 1
454 Page 454: The CRegister Class

In the CRegister class, the OnDigit() function should be declared as follows:

void OnDigit(const int& digit);

23-Feb-99 1
457 Page 457: Handling a Digit in CRegister

The parameter of the function CRegister::OnDigit() should be:

const int& digi

05-Jan-99 1
458 Page 458: Declaration of m_bBeginValue

The CRegister member variable m_bBeginValue should be declared as bool (as stated in the text) rather than int (as shown in the code).

13-Jan-99 1
459 Page 459: operator+ function

In the comments in the definition of the operator+ function, R1 and R2 should be replaced by reg1 and reg2.

09-Jun-00 1
465 Page 465: CLogicUnit contructor

The second line of code at the bottom of the page should end m_pCalc(pCalc) with an underscore rather than a hyphen.

12-Jun-00 1
470 Page 470: Register Contents Table
Some of tde values and actions shown in tde table do not accurately reflect the workings of the code.
tde lower part of tde table should appear as follows:
Key Action m_DisplayReg m_AddReg m_MultiplyReg
+ m_DisplayReg * m_MultiplyReg 3 1 6
  Copy m_MultiplyReg to M_DisplayReg 6 1 6
  m_DisplayReg + m_AddReg 6 7 6
  Copy m_AddReg to m_DisplayReg 7 7 6
4 Store in m_DisplayReg 4 7 6
Enter m_DisplayReg + m_AddReg 4 11 6
  Copy m_AddReg to m_DisplayReg 11 11 6
17-Sep-98 1
471 Page 471: Completing the CDisplay Class

The incomplete declaration of the CRegister class (which you are told to add) is missing from the contents of the file Display.h. The following line should be placed immediately above the incomplete declaration of CCalculator:

class CRegister;

05-Jan-99 1
484 Page 484 Missing Semicolon

First 3 lines of the function declaration should read:

int main()
long* pnumber = NULL;
long number1 = 55;
long number2 = 99;

Thanks to Clinton Hess

22-Feb-01 1
487 Page 487: typing error

On the final line "withhandling" should read "with handling".

09-Aug-00 1
512 Page 512: Functions Checking the Free Store

In the second sentence of the section entitled Functions Checking the Free Store, ctrdbg.h should read crtdbg.h.

12-Jun-00 1
521 Page 521: Preprocessor symbol

The preprocessor symbol _NDEBUG should be _DEBUG.

05-Jan-99 1
535 Page 535: MFC Hierarchy Diagram

The first sentence of the second paragraph on page 535 should read as follows:

Each arrow in the diagram points to a derived class from its base class.

08-Jul-99 1
618 Page 618 Typing error

The final sentence on the page should read:

. Create a new header file and add the following skeleton code:

Thanks to David Sneed

22-Feb-01 1
621 Page 621: comment wrap

In the code at the top of the page, a comment, // Get the bounding rectangle for an element, has wrapped to the next line.

12-Jun-00 1
662 Page 662 Error in code
The code snippet presented on this page should only contain one call to SetROP2 to ensure that curves are drawn with solid rather than dotted lines.
The code should therefore read as:
void CSketcherView::OnMouseMove(UINT nFlags, CPoint point)
  //Define a Device Context object for the view
  CClientDC aDC(this);
  if((nFlags & MK_LBUTTON) & (this == GetCapture()))

Thanks to Peter Schoellkopf
22-Feb-01 1
690 Page 690: Highlighting Elements

An extra argument has been included in the constructor for the line object. The final argument should not be added until the next chapter, so the constructor declaration should read as follows: CLine(const CPoint& Start, const CPoint& End, const COLORREF& Color);

20-Oct-98 1
717 Page 717: Adding Pen Widths to the Elements

The constructor declaration in the CLine class should read as follows:CLine(const CPoint& Start, const CPoint& End, const COLORREF& Color, const int& PenWidth);

20-Oct-98 1
785 Page 785: Writing Your Own DLLs

There are two references to, 'DLLs which don't involve MFC' - a topic which is not covered in the book. The first is in the bulleted list on page 785 and the second is in the 'Writing DLLs' section on page 792.

26-Oct-98 1
792 Page 792: Writing DLLs

The last sentence in the section entitled Writing DLLs which reads &quotFinally, we will cover how to write plain Windows DLLs which do not involve MFC at all." should be deleted.

12-Jun-00 1
882 Expediting the Update
Currently the database will not be updated with changed records on exiting the routine. This can be acheived by inserting the following line:
void CDBSampleView::OnEditorder()
  if( m_pSet->CanUpdate() )
      if (m_UpdateMode)
        m_EditCtrl.SetWindowText("Edit Order");
        UpdateData(true);  //Added Line
Thanks to Scott Weber

01-Dec-00 1
883 Page 883: Controlled Updating
In order to correctly cancel an update operation, an extra line needs to be added to the definition of OnCancel().
The extra line should read:
It should be inserted after the line that cancels the update operation so that the definition of OnCancel() reads as follows:
void COrderDetailsView::OnCancel() 
  m_UpdateMode = !m_UpdateMode;
UpdateData() is explained on page 898.

Thanks to Christopher Hutchinson.
22-Oct-98 1
902 Page 902: Selecting Products for an Order

​ In the definition of InitializeView(), m_CompanyName should be replaced with m_CustomerName. The fourth line in the body of the function should read:
m_CustomerName = pDoc->m_Order.m_ShipName;

29-Oct-98 1
932 Page 932: Implementation of OnUpdate()
The implementation of the OnUpdate() member function of CWrxContainerView is missing from Chapter 22. The following text should have been added immediately before the 'Setting the Tracker Style'section:

We need to override the default implementation of the OnUpdate() function in order to make use of the hint information passed in the second and third parameters. Add this function to the CWrxContainerView class using ClassWizard, giving the return type as void and the name as OnUpdate(CView* pSender, LPARAM lHint, CObject *pHint). The implementation is shown below:

void CWrxContainerView::OnUpdate(CView *pSender, LPARAM lHint, CObject *pHint)
    //We need to pass a rectangle to InvalidateRect() for the item
    //that takes account of the tracker
    CRectTracker tracker;  //The tracker
    SetupTracker((CWrxContainerItem*)pHint, &tracker);  //...setup for the item
    CRect rect;
    tracker.GetTrueRect(rect);  //Get the tracker rectangle
    InvalidateRect(rect);  //and invalidate that.
03-Dec-98 1
945 Page 945: Drawing the Document
In the OnUpdate() function, pHint is cast to CElement instead of CElement*. The line should, therefore, read as follows:
CRect aRect = static_cast<CElement*>
26-Oct-98 1
982 Page 982: Testing the Control

In the third paragraph on page 982, the menu option that you should select is:

Edit | Insert New Control
16-Feb-99 1
1045 Page 1043: Definition of OnDraw()
The contents of the file OurConstants.h should be as shown on pages 975 and 978. The full listing is given below:
//Definition of constants
#ifndef __OURCONSTANTS_H__
#define __OURCONSTANTS_H__

const int STOP          = 101;
const int GO            = 103;
const int READY_TO_STOP = 104;

const COLORREF RED      = RGB(255, 0, 0);
const COLORREF ORANGE   = RGB(200, 100, 0);
const COLORREF GREEN    = RGB(0, 255, 0);
const COLORREF GRAY     = RGB(100, 100, 100);

29-Oct-98 1
1051 Page 1051: Adding the Signal to the Control

The CSignal constructor should include the following line (which is added by the ATL COM AppWizard):

m_bWindowOnly = TRUE;
29-Oct-98 1
1051 Page 1051: Drawing the Control

In the OnDraw function definition at the bottom of the page, the first line should read


Inthe same function definition, the static_cast is inappropriate. Therefore the first line in the body of the function should read

RECT& rc = *(RECT*)di.prcBounds; // Get control rectangle

29-Oct-98 1
1053 Page 1053: Definition of StartSignal()

In the definition of StartSignal(), the call to SetSignalState() should be a call to SetState(). The second line in the body of the function should, therefore, read as follows:

m_TrafficSignal.SetState(m_bStartRed ? STOP : GO);
29-Oct-98 1
1054 Page 1054: Starting and Stopping the Signal

In the first paragraph on page 1054, SetTimer() is described as having three arguments. In fact, the version of SetTimer() used here only has two arguments, as shown in the StartSignal() function definition. The two arguments are the timer ID and the time interval in milliseconds.

29-Oct-98 1
1062 Page 1062: screenshot

The screenshot should reflect the fact that the states are 101, 103, 104 (not 101, 102, 103).

12-Jun-00 1
1065 Page 1065: Appendix A

The keywords shown below should be included in the list:


The following are not Visual C++ keywords:


29-Oct-98 1
1075 Page 1075: Answer to exercise 2-4

The answer to exercise 2-4 should have only one of the arguments in the division cast to a double, as described in the text but not as shown in the line of code. The line of code should read as follows:

double aspect = static_cast<double>(width)/height;

The code as shown in the book will produce the answer 1 (when dividing 640 by 480). This is because both width and height are integer variables and therefore the result of (width/height) will be an integer also; the nearest integer to the actual result of 1.333 being 1. Only when the division has been performed is the result cast to a double (i.e. the integer 1 is cast to the double 1.0).
In the correct version only width is cast to a double. Width is then divided by the integer height, producing a result that is a double (in this case 1.333).

25-Sep-98 1
1111 Page 1111 - Ex14-4
The code solution given for Exercise 14-4 should read as follows:
void CSketcherDoc::OnUpdateColorBlack(CCmdUI* pCmdUI)
  //Set menu item checked if the current color is black
  //Set upper case for a selected item, lower case otherwise
  if(m_Color == BLACK)
Thanks to Vincent Hand
27-Jul-01 1
1135 Page 1135: Solution to exercise 21-3

When you create the recordset class, CEmployeeSet, based on the employee table, the wizard will create the class with member variables corresponding to all the fields in the table. As you can see from the constructor shown on page 1135, most of these members have been deleted using ClassWizard, leaving only the 3 fields we need. Care should be take when deleting fields from a recordset class not to delete the key field(s).

In the second paragraph on page 1136, the text reads "To control the list box, add another variable to CCustomerView". Note that you should use ClassWizard to add this variable, m_EmployeeCtrl. As well as adding the member variable to the header file (as shown in the code snippet), the wizard will automaically add the following line to the DoDataExchange() method in the .cpp file:DDX_Control(pDX, IDC_EMPLOYEENAME, m_EmployeeCtrl);Remember that this function controls the exchange of values between data members and dialog controls.

Note that in the code shown for CCustomerView::OnInitialUpdate() at the bottom of page 1136, a call to SetNewOrderID() is shown. This is superfluous, as the method has already been called from CMainFrame::SelectView().

In the first paragraph on page 1138, the text states "the listbox handler we added to CCustomerView ...". Note that you need to add this handler at this point using ClassWizard.

26-Nov-98 1