Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Borland's C++Builder


Dr. Dobb's Journal May 1997: C Programming

By Al Stevens

Al is a DDJ contributing editor. He can be contacted at [email protected].


Last winter, Borland posted a preview edition of its C++Builder for public download. By the time this column airs, the released version will be available. In case you haven't heard, C++Builder is Delphi with a C++ dialect. What's Delphi? I'll explain soon. In the meantime, this toolset is a milestone event in Windows C++ programming. Following are some timeless (but not very timely) and somewhat prophetic (he said modestly) quotes from past editions of Dr. Dobb's Journal:

Microsoft has flattened the Windows programming ramp into a gentle slope with a product called Visual Basic, a program development environment that makes Windows programming not only a breeze, but a pleasure as well.

-- "C Programming," December 1991

Visual Basic is a great tool for constructing a quick and dirty Windows application...We really need a Visual C/C++, too.

-- "C Programming," March 1993

The success of Visual Basic was followed by cries from programmers for visual versions of other languages. Loudest of these calls came from C and C++ programmers...Visual C++ is Microsoft's answer to that cry...If you are looking for Visual Basic with a C or C++ dialect, forget it. [None] of these products is to C and Windows what Visual Basic is to Basic and Windows.

-- Windows Programming Special Issue, Fall 1993

When Visual Basic came out, I was sure that Visual C would soon follow. It did not. All contemporary C- and C++-based visual development environments that I have seen launch compilers. They are not interpreters that work like Visual Basic. It seems to me that such a program would be useful and, if done properly, wildly successful.

-- "C Programming," December 1994

That's right. All those pearls of wisdom emanated from yours truly. It almost looks like I have great powers of either prediction or persuasion. Nah. It's just that I was whining about not having what someone was bound to do eventually. In C++Builder -- codenamed "Ebony" in beta -- we are getting almost exactly what I've been wanting for over five years. It's not an interpreter, but its developer user interface is what I was begging for all that time. I predict that C++Builder will be, to again quote the old soothsayer, "wildly successful." Sooth. Sooth.

Now let's turn to something that I did not write about: Delphi. In the spring of 1995, Borland marketeers waylaid every trade journalist they could find at the Software Development 95 West conference. They shoved nondisclosure agreements at us and treated us to private screenings of their brand new development system, code named Delphi, which was a visual Windows development environment that used Object Pascal as the underlying programming language. They were quietly calling it the "VB killer." Those who had the inside track asserted that Borland was betting their foundering company on this new product.

Zack Urlocker, Borland's main Delphi developer and product manager, conducted the demonstration. I was fascinated by the Visual Basic-like interface and the clever wrapper encapsulation of the Windows API, which hides many of its knurly details from the programmer. I was not fascinated by the Pascal dialect, though. I asked the obvious question, "When are you going to do this with C++?" Zack sidestepped the question, sloughed off C++ as being inappropriate for this exciting new technology, and tried to divert my attention to more of the neat features of Delphi. That's not how you hold my attention. Needless to say, said attention wandered, and I do not remember much about the rest of the demonstration. Zack, not coincidentally, is now Borland's director of product management and, no doubt, the number one C++Builder defender. My, how times and attitudes do change.

Later at the conference I cornered a usually reliable Borland source and asked again, "When are you going to do Delphi for C++?" I was told in hushed tones that of course Borland would eventually do a C++ version, but I inferred from my confidant's conspiratorial manner that no one was allowed to admit it on the record lest the rumor should stifle potential Delphi sales.

Despite what some folks might be saying now, Delphi's code name was not Ivory (Get it? Ebony? Ivory?), at least not when they were showing it to me. It was called Delphi. At the end of the conference, a Borland manager asked my opinion about using the codename Delphi for the real name; he thought the name Delphi might suggest a developer's pathway to Oracle. (Get it? Delphi? Oracle?) He mentioned something about this being the ultimate client/server development solution. Never having met anyone outside of marketing who knows what "client/server" means, I offered no opinion about the name but asked my question one more time, "How about Delphi for C++?" He muttered something about concentrating on the promotion of this great new Pascal product and that C++ programmers would surely see the light and make the switch in order to gain access to all this cool development stuff, and then he wandered away.

Delphi was an overwhelming success, technically and otherwise. At least one of my colleagues credits Delphi's rapid application-development model for enabling him to produce a timely Windows version of his DOS product and saving his company. I never mentioned Delphi in this column because this is, after all, the C column. I talked some about Visual Basic, but VB 1.0 was a revolutionary product, the first wholly original thing to come out of Microsoft since the Altair's BASIC interpreter. And, as the quotes at the top of this column show, I was constantly lobbying for a C version.

C++Builder Arrives

A few days ago (in February, 1997) a package arrived from Borland containing a beta copy of C++Builder. As a general but not inflexible rule, I do not discuss beta software development products in print, preferring to wait for the shipping versions. I'll make an exception here for these reasons:

  • First, the product is extremely relevant to this forum, particularly in light of all the hot air I've spent over the years about wanting a true visual C/C++ Windows development environment.
  • Second, there is no nondisclosure agreement and I've already read about this thing in other magazines, so I'm free to discuss it.
  • Third, the package claims to be the "final beta version" with only a few clearly identified bugs to be worked out. Also, the "product is scheduled to ship in the next few weeks," which means that it should be released before you read this, depending on how many weeks a few weeks are.
  • Fourth, the package includes a "Reviewer's Guide," which means that they must want journalists to write about it.
  • Fifth, a preview edition of C++Builder has been available for download from the Borland web site since early January, so many of you already have it and know more about it than I do.
  • Sixth, having waited impatiently for five years, I'm excited about this product's potential and can't wait any longer to write about it.

It's not Interpreted C++

C++Builder is not the interpreter that I longed for. In this respect, it is like all the other so-called visual development environments for Windows. C++Builder launches a compiler and linker. I don't mind. A C++ interpreter would be a big, slow beast indeed. I had always envisioned a C+ language (that's right, one plus) with some but not all of the C++ extensions, that would be designed for the express purpose of supporting a visual programming model similar to that of VB -- forms with events and properties that a programmer can address as members of a structure. It occurred to me that Quincy 4.1 could grow into that language, but I never got around to growing it. It would have been a disappointment, anyway. Whatever feature I omitted from C++ in the name of efficiency would have been sorely missed. Maybe Java...

No matter. My musings about a C-plus interpreter were made in the days when 66-Mhz 486s were the leading edge and compilers were slow. C++Builder is not as fast as VB when it comes to building and running a test of an application, not even, I am told, as fast as Delphi. But it's fast enough on a P-133, particularly now that Visual C++ has accustomed me to those compile-then-link-then-execute coffee breaks, er, delays.

This Isn't Your Father's Visual C++

C++Builder uses an intuitive user interface that reminds me a lot of VB. The programmer's view of forms and their properties, and the programmer's navigation from a dialog control to its code, is very close to the way that VB did it. This is not only good, it is far better (in my opinion) than anything in C++ territory that I've seen so far, particularly if you are just breaking into Windows programming. Its underlying class structure is neither MFC (whew!) nor OWL (double-whew!). Instead, C++Builder builds applications around Borland's Visual Component Library (VCL), about which I have no opinions because I don't know much about it. VCL is a class library shared with Delphi. I assume that VCL is Delphi's Object Pascal library with a C++ wrapper. Borland says, "You should have a good working knowledge of VCL." That should go without saying. You should thoroughly understand any class library that you use. My VCL knowledge is extremely limited. Never one to heed my own counsel, I am publishing a C++Builder program in this column. It remains to be seen whether you also need a good working knowledge of the Win32 API as virtually every other framework class libraries requires.

What I Don't Like

Normally I wouldn't discuss bugs in a beta release, but Borland has listed those they plan to fix, and these are not among them. Some of the items in this list are not necessarily bugs -- just things that I wish they had done differently. If you are already a staunch C++Builder devotee, feel free to disagree. But before firing off a flame, please know that these are the few things that I view as being wrong about C++Builder. A whole lot more about it is dead bang on.

A tutorial that is similar to VC++'s venerable Scribble application would be helpful, but I did not find one. There are several example programs, though. Borland is notorious for publishing documentation that most programmers find wanting. Watch for a spate of bad books from mostly unqualified authors to hit the bookstores precisely when the product ships. Watch for a few good ones, too. I haven't seen the C++Builder manuals yet, but the Help database lacks a lot of details. Many VCL items have no entry at all. For example, put the editor's insertion cursor on the ToInt or ToDouble identifiers -- member functions in the AnsiString class -- and press F1. Nothing.

Here's some buggy behavior I found in the IDE. In the simplest of applications, you view one code window and one form on the screen. The code window is a tabbed page that can display multiple source code files. You can open more than one of these, but assume for the moment that you have what comes up as the default. Add some controls to the form; invest a lot of time, so you'll have something to really complain about. Decide that you want to close the code window. Click the "X close" icon in the code window's title bar. Although you made no changes to the source code .cpp file, C++Builder asks if you want to save the changes to the file. (You didn't make any changes, but C++Builder did when it built the initial version of the file.) If you change your mind and do not want to close the window, your first impulse is to click Cancel. That's what you would do in any other application with a dialog box that has Yes, No, and Cancel buttons. C++Builder flies in the face of convention and closes the complete project without saving the changes you made to the form -- most unfriendly and most costly in terms of your time. It made me say words I haven't said since my dear, sweet daughter eloped with an illegal alien. I don't know if Delphi works that way, but they need to fix that feature in C++Builder if they're going to capture the hearts of us C++ programmers.

Pointers. Why did they use pointers? The VB programming model allows you to address a form's properties and methods as if they were data members of a QBasic TYPE declaration. It follows that a C/C++ implementation would similarly use the dot (.) structure member operator to address properties and methods of a form. That's how OWL and MFC work. Somewhere along the way, however, Borland made a different design decision for C++Builder and implemented the instantiation of forms and their members through pointers. You have to use pointer (->) operators to address them. I don't like that. It has an inherently unstable feeling to it. Pointers and pointer arithmetic, and the fact that you can modify a pointer's value, are all sources of many bugs in C and C++ programs. They're not even implemented as const pointers (as opposed to pointers to const) to keep you from changing their initial values. Borland should have spent a little more time working on that behavior and figured a way to use references or, better still, embedded objects like MFC does. That way, the data structure would be more stable and our code could use the more intuitive dot operator.

C++Builder does not throw an exception if you try to divide by zero. Instead, it jumps over the statement -- behavior that could cost you time looking for a bug in your program. Clearly, if it knows enough to ignore the expression, it could know enough to mimic other compilers (such as Borland C++ 4.5) and throw an exception or exit the program or something equally intelligent.

My first C++Builder program, which I will describe soon, originally had a class named Date. The compiler reported an ambiguity between the call to my constructor and a function named Date in the VCL Sysutils namespace. I thought that was what namespaces were for -- to isolate hidden global identifiers from your program -- but the compiler's sysutils.hpp file puts everything in the Sysutils name-space and then ends with the statement in Example 1(a), which puts everything that was in the Sysutils namespace back into the global namespace, which effectively neuters the Sysutils namespace. If you want to use the identifier Date for anything, or any other identifier that they might have appropriated, you have to shroud it in your own namespace, which is a real pain in the outback. I changed my class's name to CalendarDate to get around the inconvenience.

There are other namespace problems. I tried using the new ANSI header file format to include the standard C++ string class as in Example 1(b). That usage generated multiple warnings associated with the std namespace. I had to revert to including Borland's <cstring.h> header file to use the Standard C++ string class. It should generate the same code as what I tried to do, but, heck, I like staying up to date with things.

There are other header-file inconsistencies. Borland implemented only some of the new header files. They failed to implement those that place the Standard C library within the std namespace (<cstdio>, <cstring>, <cstdlib>, and so on).

I don't think that Borland has name-spaces working yet. That's okay; neither does anyone else. (Duck, Al, here comes the e-mail.)

C++Builder supports exception specifications in most function declarations and definitions but not if the function is one that C++Builder adds to a form class to support a control event, such as the click of a button. The compiler reports an "incorrect method declaration" in the member function's declaration within the class declaration. I'm sure only of that one inconsistency. The compiler might reject other exception specifying function declarations, too. I was able to add an exception specification to my CalendarDate class's constructor, however.

C++Builder introduces a few confusing administrative conventions. It assigns names to the project and form -- uninteresting names like Project1 and Unit1. The files use those names with .cpp and .h extensions. You can save the files with other names and the system updates everything accordingly. I renamed the Unit1.cpp file to Amort.cpp to reflect the purpose of the program, which is to produce an amortization schedule. Then I tried to save the project itself under that same name. The project is represented by a .MAK file. C++Builder objected, saying that there was already something with that same name. It took a while to observe that when you choose to compile a source code file by itself, C++Builder builds a temporary .MAK file for that purpose, and it does not want you using the same name twice.

To support the first version of OWL back in the old days, Borland extended the C++ language with new keywords to support window message maps. Many programmers found that to be an objectionable construction particularly since Microsoft's MFC achieved the same result by using preprocessor macros within the rules of the proposed standard language. Later versions of OWL wisely (Get it? OWL? Wisely?) dropped the extended language features. I guess somebody took a look at MFC and saw how it ought to be done. Now Borland is back at it again. They apparently identify class members that C++Builder generates by using a new access specifier called __published. (There are other new keywords used for different things.) It's almost funny. MFC uses special comment tags for the same purpose, a construction that does not violate standard language rules. Maybe Borland's Ebony programmers ought to take another peek at the MFC source code.

The Amortization Application

Upon my first exposure to Visual Basic 1.0 in 1991, I set out to write a simple application -- a Novell e-mail program that ran on a LAN. The whole thing involved only 640 lines of code and took four days from shrink wrap to completion, including (I said then):

...learning Visual Basic, relearning the fundamentals of the Basic language, learning something more about Windows programming, designing the program and its data structures, and, oh yes, writing the code.

That experience accounted for my enthusiasm at the time about Visual Basic.

Recently I needed a loan amortization program. I have one that I wrote in QBasic for an introduction to programming book, but it's a clunky old DOS application, and I always have to ensure that QBasic is installed whenever I want to run the program. This seemed a good way to introduce myself to C++Builder, so I started that task. To my delight, the whole job took less than one day and involves only 395 lines of code, much of which I did not write -- C++Builder wrote it.

An amortization schedule is a listing of loan payments that spans the full term of the loan and reports the date of each payment, the amount of interest and principal that each payment represents, and the payoff balance at the time of each payment. The schedule provides interest and principal totals at the end of each year. If the loan includes a balloon payment date, the schedule reports the balance due on that date. The input to such a schedule is the amount loaned, the interest rate, the term of the loan in years, and the two dates.

Listings One and Two are Date.h and Date.cpp, which implement a CalendarDate class to support the amortization schedule's payment date and balloon payment date. The class constructor takes a pointer to a character string, presumably a date that the user enters in mm/dd/yy format. The constructor builds a CalendarDate object from the string while validating the entry. If the entry is invalid, the constructor throws an exception. The class's BuildDateDisplay member function builds a display of the CalendarDate object based on its month, day, and year data member values. There is a NextMonth function that increments the date to the next calendar month, an IsDecember function so that the class user knows when the date is about to increment to the next year, and overloaded == and != operators for comparing the balloon payment date to the current payment date as the program builds the schedule display.

Listings Three and Four are mortgage.h and mortgage.cpp, which implement a Mortgage class. The class is a simple struct with five data members and one member function to compute the payment. Don't ask me to explain the payment computation algorithm. I got it out of a real estate book many years ago, and it's always worked to within a penny of what a bank or realtor tells me.

Listing Five is amort.cpp, which implements the application layer of the program. I did not write this source-code file. C++Builder did.

Listings Six and Seven are mortdata.h and mortdata.cpp, which implement one of the two forms created by the application. This form is where the user enters the data values that describe the loan. My only contributions to mortdata.h were the addition of two private data members -- an instance of the Mortgage class and a Bool variable that records whether the user input data values represent a valid mortgage.

The ComputeClick member function of the form contains some of my code. It executes when the user clicks the form's Compute Payment button, validates the input data, and displays the computed payment on the form.

The DisplayScheduleClick member function of the form also contains some of my code. It executes when the user clicks the form's Display Schedule button. It calls the ComputeClick function to recompute and validate the input data. Then, if the input data values passed the validation, the function further validates the form by instantiating CalendarDate objects from the date entries. If they pass, the function calls the DisplaySchedule function of the other form in the application.

Listings schedule.h and schedule.cpp implement the TSchedule class, which supports the other form in the application. That form contains a simple listbox that displays the amortization schedule. The TSchedule::DisplaySchedule member function accepts a reference to the Mortgage object that the other form constructs and builds the listbox by using the values in the Mortgage object. First the function calls the listbox class's Show member function, which is a member of a base class somewhere up the VCL hierarchy. Show opens the form window if it hasn't been opened, displays it, and brings it to the top. The Clear function, also a member of a base class, clears any previous displays from the listbox. Then the DisplaySchedule function iterates through the dates in the mortgage period computing and displaying the details of each payment.

And that's all there is to that. There are three other files associated with the amortization schedule project. One is the project's .MAK file and the other two are non-text .DFM files that describe the form layouts. I want to take the project farther and learn even more about C++Builder. For one thing, , I'd like to print the schedule. The entire project is available electronically; see "Availability," page 3.

My enthusiasm for C++Builder is unbridled at the moment. I plan to use it for something more significant when time permits. When I do, I'll let you know how it goes.

DDJ

Listing One

// ---- date.h#ifndef DATE_H
#define DATE_H


</p>
#include <cstring.h>


</p>
class BadDate { };


</p>
class CalendarDate  {
   int m_nMonth, m_nDay, m_nYear;
    int ExtractDateComponent(const char** pText, int min, int max);
    void AppendDateComponent(string& rstrDate, int nComponent,
                        bool bAddSlash = true) const;
public:
    CalendarDate(const char* pText = 0) throw(BadDate);
    void BuildDateDisplay(string& rString) const;
    bool IsEmpty()
        { return m_nMonth == 0 && m_nDay == 0 && m_nYear == 0; }
    void NextMonth();
    bool IsDecember() const
        { return m_nMonth == 12; }
    bool operator==(const CalendarDate& rDate) const
        { return rDate.m_nMonth == m_nMonth &&
                 rDate.m_nDay   == m_nDay   &&
                 rDate.m_nYear  == m_nYear; }
    bool operator!=(const CalendarDate& rDate) const
        { return !(*this == rDate); }
};
#endif

Back to Article

Listing Two

// --- Date.cpp#include <stdlib.h>
#include <ctype.h>
#include "Date.h"


</p>
// --- extract a Date component (mm/dd/yy) from a Date string
int CalendarDate::ExtractDateComponent(const char** pText, int min, int max)
{
    while (isspace(**pText))
        (*pText)++;
    int nComponent = atoi(*pText);
    if (nComponent < min || nComponent > max)
        throw BadDate();
    while (isdigit(**pText))
        (*pText)++;
    while (isspace(**pText))
        (*pText)++;
    return nComponent;
}
// --- construct a Date object from a Date string (mm/dd/yy)
CalendarDate::CalendarDate(const char* pText) throw(BadDate)
{
    m_nMonth = 0;
    m_nDay = 0;
    m_nYear = 0;
    if (pText == 0)
        return;
    m_nMonth = ExtractDateComponent(&pText, 0, 12);
    if (m_nMonth == 0 && *pText == '\0')
        return;
    if (*pText != '/' )
        throw BadDate();
    pText++;
    m_nDay = ExtractDateComponent(&pText, 1, 31);
    if (*pText != '/' )
        throw BadDate();
    pText++;
    m_nYear = ExtractDateComponent(&pText, 0, 99);
    if (*pText != '\0' )
        throw BadDate();


</p>
    // --- validate day based on month, year
    if (m_nMonth == 2)  {
        if (m_nDay > 29 || (m_nDay == 29 && ((m_nYear % 4) || m_nYear == 0)))
            throw BadDate();
    }
    else if (m_nDay == 31)
       if (m_nMonth == 4 || m_nMonth == 6 || m_nMonth == 9 || m_nMonth == 11)
            throw BadDate();
}
// --- append to a display string a component of a Date object
void CalendarDate::AppendDateComponent(string& rstrDate, int nComponent,
                                            bool bAddSlash) const
{
    if (nComponent < 10)
        rstrDate += "0";
    char str[5];
    itoa(nComponent, str, 10);
    rstrDate += str;
    if (bAddSlash)
        rstrDate += "/";
}
// --- build a display string from a Date object
void CalendarDate::BuildDateDisplay(string& rstrDate) const
{
    rstrDate = "";
    AppendDateComponent(rstrDate, m_nMonth);
    AppendDateComponent(rstrDate, m_nDay);
    AppendDateComponent(rstrDate, m_nYear, false);
}
// --- increment date by one month
void CalendarDate::NextMonth()
{
    if (++m_nMonth == 13)   {
        m_nMonth = 1;
        if (++m_nYear == 100)
            m_nYear = 0;
    }
}

Back to Article

Listing Three

// ---- mortgage.h#ifndef MORTGAGE_H
#define MORTGAGE_H


</p>
#include "Date.h"
struct Mortgage {
    double m_nPrincipal;            // loan amount in $
    double m_nInterest;             // monthly interest rate
    int m_nTerm;                    // loan term in months
    CalendarDate m_PaymentDate;     // date of first payment
    CalendarDate m_BalloonDate;     // date of balloon payment
    double Payment();               // compute and return monthly payment
};
#endif

Back to Article

Listing Four

// --- mortgage.cpp#include <math.h>
#include "mortgage.h"
double Mortgage::Payment()
{
    double nPayment = ((double)((long)(((m_nPrincipal*m_nInterest)/
        (1-pow((1/(1+m_nInterest)),m_nTerm))+.005)*100)))/100;
    return nPayment;
}

Back to Article

Listing Five

//---------------------------------------------------------------------------#include <vcl\vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("mortdata.cpp", Form1);
USERES("Amort.res");
USEFORM("Schedule.cpp", Schedule);
USEUNIT("Date.cpp");
USEUNIT("mortgage.cpp");
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    try
    {
        Application->Initialize();
        Application->CreateForm(__classid(TForm1), &Form1);
        Application->CreateForm(__classid(TSchedule), &Schedule);
        Application->Run();
    }
    catch (Exception &exception)
    {
       Application->ShowException(&exception);
    }
    return 0;
}
//---------------------------------------------------------------------------

Back to Article

Listing Six

//---------------------------------------------------------------------------#ifndef AmortH
#define AmortH
//---------------------------------------------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\Menus.hpp>
#include "mortgage.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TLabel *Label1;
    TLabel *Label2;
    TLabel *Label3;
    TLabel *Label4;
    TLabel *Label5;
    TLabel *Label6;
    TEdit *Principal;
    TEdit *Interest;
    TEdit *Term;
    TEdit *PaymentDate;
    TEdit *BalloonDate;
    TButton *Compute;
    TLabel *Payment;
    TButton *DisplaySchedule;
    void __fastcall ComputeClick(TObject *Sender);
    void __fastcall DisplayScheduleClick(TObject *Sender);
private:    // User declarations
    Mortgage m_Mortgage;
    bool m_bScheduleOK;
public:     // User declarations
    virtual __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Back to Article

Listing Seven

//---------------------------------------------------------------------------#include <vcl\vcl.h>
#pragma hdrstop


</p>
#include <strstream>
#include <iomanip>
#include "mortdata.h"
#include "schedule.h"
#include "Date.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComputeClick(TObject *Sender)
{
    m_bScheduleOK = false;
    bool bPrincipalOK = false;
    if (Principal->Text != "")  {
        m_Mortgage.m_nPrincipal = Principal->Text.ToDouble();
        bPrincipalOK = m_Mortgage.m_nPrincipal > 0;
    }
    if (!bPrincipalOK)  {
        MessageBox(0, "Invalid principal amount", "Error", MB_ICONERROR);
        return;
    }
    bool bInterestOK = false;
    if (Interest->Text != "")   {
        double nInterest = Interest->Text.ToDouble();
        m_Mortgage.m_nInterest = nInterest / 100 / 12;
        bInterestOK = nInterest > 0;
    }
    if (!bInterestOK)   {
        MessageBox(0, "Invalid interest amount", "Error", MB_ICONERROR);
        return;
    }
    bool bTermOK = false;
    if (Term->Text != "")   {
        m_Mortgage.m_nTerm = Term->Text.ToInt() * 12;
        bTermOK = m_Mortgage.m_nTerm > 0;
    }
    if (!bTermOK)   {
        MessageBox(0, "Invalid term", "Error", MB_ICONERROR);
        return;
    }
    m_bScheduleOK = true;
    double nPayment = m_Mortgage.Payment();


</p>
    strstream strPmt;


</p>
    strPmt << setprecision(2)
           << setiosflags(ios::fixed | ios::right)
           << nPayment;
   Payment->Caption = strPmt.str();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DisplayScheduleClick(TObject *Sender)
{
    ComputeClick(Sender);
    if (m_bScheduleOK)  {
        try {
          m_Mortgage.m_PaymentDate = CalendarDate(PaymentDate->Text.c_str());
          if (m_Mortgage.m_PaymentDate.IsEmpty())
                throw BadDate();
          m_Mortgage.m_BalloonDate = CalendarDate(BalloonDate->Text.c_str());
          Schedule->DisplaySchedule(m_Mortgage);
        }
        catch (BadDate) {
            MessageBox(0, "Invalid date", "Error", MB_ICONERROR);
            return;
        }
    }
}
//---------------------------------------------------------------------------


</p>

Back to Article


Copyright © 1997, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.