📄 manual.txt
字号:
*text);
...
}; //class Integer
...
void Integer::GetErrorText(const long errorCode, char *text)
{
switch (errorCode)
{
case errIntDivByZero : strcpy(text, "Divide by zero in
Integer object.");
break;
case errIntOverflow : strcpy(text, "Value too large
for Integer object.");
break;
default :
AlertableObject::GetErrorText(errorCode, text);
break;
}; //switch statement to determine error text
}; //member function Integer::GetErrorText
To invoke the use of your strings in your member functions,
you simply call the appropriate Handle*() member function,
passing the correct alert constant. As always, you should
call the appropriate Handle*() member function from the
member function where the alert is first encountered.
Because the Handle*() member functions automatically call
the Get*Text() and Report*() member functions, a simple call
to the appropriate Handle*() member function sets the entire
chain of events into motion.
At first, this may seem like a roundabout way of doing
things, until you realize the amount of flexibility and
reusability that your code gains. Because the Get*Text()
member functions are virtual, you can override them in
descendant classes. If you don't like the text for a
specific alert code, you can derive a new class and return a
different string for the code, even if you don't have the
source code for the original class. The Get*Text() member
functions don't even have to store the alert text in the
program; the functions can be written to retrieve the alert
text from an external text file. Using an external file to
store the strings for each alert allows an application to
use a minimal amount of program memory to store text. In
addition, the text file can later be altered to update
existing alert text without requiring recompilation of the
application. Coupled with the platform-independent output of
the AlertDriver, these capabilities give every
AlertableObject maximum flexibility in presenting alerts to
the user.
Example 11 demonstrates how the overloaded "/" operator
handles errant attempts to divide Integer objects by zero.
Example 11 - The overloaded operator member function
Integer::operator /() calls inherited member function
HandleError() whenever it detects an attempted divide by
zero. Invoking the HandleError() member function causes an
eventual call to the Integer::GetErrorText() member function
shown in Example 10.
int Integer::operator / (int aValue)
{
int result; //holds the function result
if (aValue)
//specified value is not 0
result = val / aValue;
else
{
HandleError(errIntDivByZero);
result = INT_MAX;
}
return result;
}; //overloaded operator Integer::operator /
Changing & Sharing AlertDrivers
All programs linked with the AlertDriver Class Library
automatically gain access to a default AlertDriver
referenced by the defaultAlertDriver pointer (defined in
ALERTDRV.H). This global AlertDriver is usually an
interactive, screen-oriented driver which provides alert
reporting capabilities for the software environment for
which the program was targeted. For example,
defaultAlertDriver may provide text-mode output for a text-
mode program, but will use Windows dialog boxes if the
program has been compiled as a Windows application. Because
defaultAlertDriver is available to be called from any part
of your application, even your non-object code can call
defaultAlertDriver's member functions (see Example 12).
Calling one of the Handle*() member functions of the
AlertDriver class is equivalent to calling one of the
AlertableObject::Report*() member functions (see the Class
Library Reference for details).
Example 12 - Accessing defaultAlertDriver's member functions
from non-object code. Calls made in this way are roughly
equivalent to the quick-and-dirty method of reporting alerts
from within objects.
#include <alertdrv.h>
...
void main(void)
{
...
//test the defaultAlertDriver without an object
defaultAlertDriver->HandleInfo(
"Text from non-object code.");
...
}; //function main()
Each AlertableObject (and derived object) that is created by
your program initially uses the defaultAlertDriver as its
AlertDriver. By using this common AlertDriver, the
AlertableObjects in your program gain all of the benefits of
platform-independent error reporting with a minimum of
code/data overhead. One AlertDriver controls the alerts of
all your program's objects.
There are times, however, when you may want to change this
default behavior, particularly if the default AlertDriver
does not provide the appropriate type of output for your
object. For example, although the default AlertDriver is
usually screen-oriented, your may want your object to log
alerts to a disk file.
You can easily change the type of AlertDriver used by your
object by calling the
AlertableObject::ChangeLinkedAlertDriver() member function.
To call this inherited member function, you create a new
AlertDriver object, then pass its address as a parameter to
the function. Because all AlertDrivers should be allocated
on the heap, this can usually be accomplished with one line
of code. For example, the following line of code will change
the AlertDriver for object MyObj to an AlertDriver which
logs alerts to a text file named "myobj.log":
MyObj.ChangeLinkedAlertDriver(new
TextFileAlertDriver("myobj.log", radFREERESOURCE));
(The radFREERESOURCE constant forces the TextFileAlertDriver
to free (close) the file whenever it is not in use; when the
file is closed (not recording alerts), it can be accessed by
other TextFileAlertDrivers or other applications. See the
Class Library Reference for more details on controlling the
TextFileAlertDriver.)
AlertDrivers allocated by your application can serve several
AlertableObjects at once, just as the default AlertDriver
originally serves all of the objects in your program as they
are created. Example 13 demonstrates how to share one newly
allocated AlertDriver among two objects.
Example 13 - Creating an AlertDriver object and sharing it
among multiple objects. In this case, both objects will log
their alerts to the same text file. Remember, AlertDrivers
which you create within your program should always be
allocated on the heap.
...
AlertDriver *pAlertDriver;
Integer a, b;
...
/*log a and b alerts to the same text file -
other AlertableObjects continue to use
defaultAlertDriver*/
pAlertDriver =
new TextFileAlertDriver("myobjs.log",
radFREERESOURCE);
a.ChangeLinkedAlertDriver(pAlertDriver);
b.ChangeLinkedAlertDriver(pAlertDriver);
...
To completely remove (not replace) the AlertDriver for an
AlertableObject, call member function
ChangeLinkedAlertDriver() with a parameter of NULL; doing
this will remove all alerting capabilities for the
AlertableObject.
The AlertDriver Class Library defines the standard classes
StdAlertDriver and TextFileAlertDriver for all software
platforms and environments. StdAlertDriver uses the standard
C++ iostreams cin, cout, and cerr to report alerts to the
user while TextFileAlertDriver logs alert text to a file
which is specified in its constructor. Additional
AlertDriver classes may be defined for your specific
software environment (for example, class
TurboVisionAlertDriver is defined for programs using
Borland's Turbo Vision class library). See the Class Library
Reference chapter for full details on the AlertDriver
classes which are available in your specific software
environment.
Experienced programmers know that one of the toughest parts
of debugging a program is finding heap allocation errors.
Because all AlertDrivers are allocated on the heap and may
be shared among multiple AlertableObjects, you may be
wondering if there is an easy way to determine when an
AlertDriver is no longer being used and when it is safe to
deallocate an AlertDriver. The answer is simple: you don't
have to worry about deallocating any AlertDrivers, even
those which you allocate! The AlertDriver Class Library
handles it all for you!
Each AlertDriver contains a count of the number of
AlertableObjects using its services. This count is
incremented each time an AlertDriver is "attached" to an
AlertableObject. An AlertableObject is "detached" from an
AlertDriver whenever the AlertableObject is deallocated,
goes out of scope, or is attached to a different AlertDriver
object through member function ChangeLinkedAlertDriver();
each time this happens, the attached AlertDriver's count is
decremented. When the count reaches zero (the AlertDriver is
no longer being used by any object), the AlertDriver is
automatically shutdown and deallocated. What this means to
you as a programmer is that you can allocate as many
AlertDrivers of as many different classes as necessary and
attach them to as many AlertableObjects as you desire with
the understanding that each of the AlertDrivers will be
deallocated as soon as it is no longer being used.
Linking AlertDrivers
Although you can change the AlertDriver used for each of
your objects at any time, this still may not give you the
level of flexibility you need. After all, it's nice to be
able to switch between screen-based alerting and logging
those alerts to a disk file, but what if you wanted to do
both at the same time? With the AlertDriver Class Library,
you can attach several AlertDrivers together in series so
that the same alerts are reported in multiple ways. This
process is known as "linking" the AlertDrivers.
To link one AlertDriver to another, you must call the
ChangeLinkedAlertDriver() member function of the first
AlertDriver object. (The first AlertDriver object is defined
as the AlertDriver which is attached to an AlertableObject,
the remaining AlertDrivers are each attached to the
previously linked AlertDriver. In effect, the AlertDrivers
form a linked list, often referred to as a "chain.") A
common use of linking AlertDrivers is to provide disk file
logging in addition to screen alerting by linking a
TextFileAlertDriver to an AlertableObject's AlertDriver.
This can be most easily accomplished if the
AlertableObject's AlertDriver is the default AlertDriver
(see Example 14).
Example 14 - By linking a TextFileAlertDriver to the default
AlertDriver, all objects using the default AlertDriver will
report their alerts to both the screen and a disk file
(assuming that the default AlertDriver reports alerts to the
screen).
...
//attach a text file AlertDriver to the default driver
defaultAlertDriver->ChangeLinkedAlertDriver(
new TextFileAlertDriver("adtest.log", radFREERESOURCE));
...
It is important to note that when you call
AlertableObject::ChangeLinkedAlertDriver() or
AlertDriver::ChangeLinkedAlertDriver(), you are effectively
replacing all AlertDrivers which are linked to the
object/driver with the AlertDriver you specify. For
illustration, assume that prior to calling the code in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -