📄 manual.txt
字号:
platforms and/or hardware devices and linked into programs
written for the AlertDriver Class Library with no change to
the underlying application logic or AlertableObject source
code.
With the concepts described to this point and their inherent
programming power and flexibility, most class libraries
would stop here. However, the AlertDriver Class Library
provides solutions to even more programming problems. An
AlertDriver object itself can reference another AlertDriver
object, effectively chaining, or linking, the AlertDrivers.
By linking the AlertDrivers for an AlertableObject, the
AlertableObject can report a single error in multiple ways
(for example, an error can be reported to the screen and
logged in a disk file). AlertDrivers can be attached and
detached from AlertableObjects in any combination at either
compile-time or run-time for maximum program efficiency and
flexibility.
Each AlertDriver can also have its actions controlled at
either compile-time or run-time via a set of processing
flags. Error-handling, for example, can be temporarily
turned on or off for each AlertDriver without the need to
disconnect or destroy the driver. Other useful processing
flags, which allow a tremendous amount of control over the
AlertDriver during run-time, are also available.
The AlertDriver library also mirrors the concepts of client-
server technology: each AlertableObject can be considered
to be a client, each AlertDriver a server. The client
initiates an action (i.e.: report an error message) and
each server has the ability to perform that action. Multiple
clients can be attached to a single server and a client may
be served by multiple servers.
The ability to connect several AlertableObjects to the same
AlertDriver allows applications to retain all of the
advantages previously discussed while minimizing the amount
of memory overhead needed to implement those features. For
example, in a spreadsheet application, each spreadsheet
object could can be derived from an AlertableObject. If each
cell required its own AlertDriver, then available memory
would decrease rapidly as the spreadsheet grew. However, by
allowing each cell to share a common AlertDriver, the memory
needed to implement AlertDriver processing is held to a
small, fixed amount (the amount needed to allocate the
common AlertDriver). Since all cells in a spreadsheet
normally report errors in the same manner anyway, the
unnecessary allocation of duplicate AlertDriver objects is
avoided.
In the next chapter, we will discuss how easily your
programs can use the AlertDriver Class Library as we step
through a tutorial.
Chapter 3 An AlertDriver Tutorial
Creating New Objects
To use the AlertDriver Class Library, you must include the
following line in your source code file:
#include <alertobj.h>
The ALERTOBJ.H header file contains the declaration for the
AlertableObject class. (The implementation of the
AlertableObject class is supplied in a separate object code
file which is platform-dependent - see the Compiling &
Linking chapter for details on compiling and linking your
code with the supported compilers/platforms.)
To create classes of your own, you simply derive your class
from AlertableObject using public inheritance. (For purposes
of demonstration, we will present a simple, and admittedly
contrived, sample class named Integer, which by itself
doesn't really do anything useful, but will allow us to
demonstrate the proper syntax and implementation of the
AlertDriver library concepts - sample platform-independent
source code implementing Integer is included with the
AlertDriver Class Library.) Your class will automatically
inherit the member functions and data of AlertableObject
(see Example 7).
Example 7 - To derive your own classes, derive your class
from AlertableObject using public inheritance.
class Integer : public AlertableObject
{
...
/*declare class-specific member
functions and data members here*/
...
}; //class Integer
Programmer-Defined Codes, Detection, & Reporting
Once you have inherited the capabilities of the
AlertableObject class, you will want to access that
functionality from your member functions. There are two
basic ways of using the AlertableObject member functions to
alert the user of program conditions: the "quick-and-dirty"
method and the "preferred" method.
The Quick-And-Dirty Reporting Method
The quick-and-dirty method of using the AlertDriver Class
Library is usually used during program testing and/or
debugging. Using this method, your object passes a literal
string to the attached AlertDriver to alert the user of the
program's condition. The quick-and-dirty method retains the
platform-independent output of the AlertDriver, but the
messages themselves are hard-coded into the program, clearly
not the most elegant solution. However, this method is the
quickest and easiest to use for quickly getting a test
program to work or for porting existing programs to the
AlertDriver Class Library. Programs written using the quick-
and-dirty method can easily be ported to the preferred
method later.
To use the quick-and-dirty method, your code calls one of
the Report*() member functions. There are four such
functions (see the Class Library Reference chapter for
details), one for each type of alert: ReportError(),
ReportInfo(), ReportMessage(), and ReportWarning().
(ClearMessage(), a related function used in conjunction with
member function ReportMessage(), clears the last message
posted.)
Example 8 shows how the code in Integer::TestAlertDriver()
makes calls to these functions, passing literal strings to
each; the AlertDriver for the Integer object reports those
strings to the appropriate output device/platform.
Example 8 - Calling the Report*() member functions inherited
from AlertableObject. Each of these inherited functions
passes the string along to the object's AlertDriver.
void Integer::TestAlertDriver(void)
{
...
//test literal strings
ReportMessage("Literal: This is a message string.");
ReportError("Literal: This is an error string.");
ReportWarning("Literal: This is a warning string.",
adsYES);
ClearMessage();
}; //member function Integer::TestAlertDriver
One final note on reporting alerts: the Report*() function
should always be called from the member function where the
alert is first encountered or generated. By consistently
following this suggestion, the code which calls your member
functions can be written to assume that any alerts occurring
within your member functions have already been reported by
the time the function returns.
The Preferred Reporting Method
The preferred method of reporting alerts requires a bit more
work than the quick-and-dirty method, but results in code
which is infinitely more reusable and flexible. We highly
suggest that any new programs and/or objects be written
using the preferred method of alert reporting, as the
preferred method results in programs which are better
structured than programs using the quick-and-dirty method.
Before we explain how to use the preferred method, we must
first discuss the concepts of using programmer-defined codes
for the alerts. Each unique alert for a class can be
assigned a unique constant value for that type of alert
within the class. For example, the error codes for the
Integer object are numbered starting at one (1). Each unique
warning alert for the Integer object is also represented
with a code, with the first warning also being number one
(1). The fact that both alerts have a code numbered one (1)
does not cause a conflict - each type of code is used in its
own context. Using constants (or #defines) to represent
these codes in your program will help both you and other
programmers to identify the different contexts when
reviewing your code (see Example 9). While you may use
negative numbers as alert code constants, do not use zero
(0) as an identifier for an alert code - zero is pre-defined
by the AlertDriver Class Library for each alert type as the
constants errOK, infoOK, msgOK, and warnOK. Alert codes are
represented by long integers.
Example 9 - Define constants to uniquely identify each alert
within a class. Each constant for a particular type of alert
within a class may have the same value as the constant
identifier of another alert type in the same class. Each
constant may also be equal to constants of the same alert
type in other classes.
...
//define alert constants for class Integer
const long errIntDivByZero = 1;
const long errIntOverflow = 2;
const long infoIntConstruct = 1;
const long msgIntDestruct = 1;
const long warnIntChange = 1;
/*legal - different types of alerts*/
...
//define alert constants for class DiskFile
const long errDiskFileNotFound = 1; //legal
const long errDiskFileDiskFull = 1;
/*illegal - same error code (1) defined
twice for same class*/
...
Because errors are the most serious types of alerts, they
should be returned from member functions whenever possible.
This means each member function should return the error code
of any error generated within that function, or return the
error code returned by functions it calls. By adhering to
this principle, the program module which calls your member
functions will always receive an error code denoting the
first error encountered during execution of your function.
Of course, your functions should return errOK if no errors
occur.
The use of programmer-defined alert codes figures
prominently in the preferred method of alert presentation.
Rather than call the Report*() member functions, your member
functions call the inherited Handle*() member functions.
Each Handle*() member function corresponds to one of the
Report*() member functions; the Handle*() member functions
are: HandleError(), HandleInfo(), HandleMessage(), and
HandleWarning().
Each of the Handle*() functions is passed an alert code as a
parameter. This alert code is then passed to one of the
Get*Text() member functions, converted to text, and the text
is passed to one of the Report*() functions. Of course,
there are four Get*Text() member functions: GetErrorText(),
GetInfoText(), GetMessageText(), and GetWarningText().
To use the preferred method of alerting, your object must
declare the appropriate alert constants for alerts which can
be generated within your object. You then override the
Get*Text() functions to convert those constants to strings.
In a well-developed class hierarchy, if your Get*Text()
function receives an alert constant which it cannot convert,
it should call the overridden Get*Text() function, as the
constant may represent an alert which was defined in a
parent class. The original Get*Text() member functions in
AlertableObject produce generic messages (i.e.: "Error 422
encountered.") for unrecognized alert codes. Example 10
shows the implementation of the GetErrorText() member
function for the Integer class.
Example 10 - Implementation of Integer::GetErrorText()
member function. Notice how error codes which are
unrecognized by this class are passed back to the overridden
function.
...
//define error constants for class Integer
const long errIntDivByZero = 1;
const long errIntOverflow = 2;
...
class Integer : public AlertableObject
{
...
public:
virtual void GetErrorText(const long errorCode, char
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -