A similar technique to the one above may be used to report errors.
A typical way to report errors is to just shove them out cerr:
Suppose you want to write a piece of code to be used in a large number of different environments where you can't predict where you will want the error messages to go. It could be that this new module will be used as part of a program that wants to log all the error messages, and also in another program that wants the error messages to be sent to a dialog box. In some cases you may want the program to supress certain error messages, in other cases you may want to change the printed message. Basically in reusable code you want complete control over the error handling at the top level, but you don't want the lower levels that generate the messages to have to know anything about the calling program.
One possible strategy is to implement a call back system just like the MODEL_VIEW class above. Each class would be derived from an error handling class that keeps track of an error reporting function or several of them for each object. The top level code would simply register the error reporting function with each object as it is created. The error function need only receive a character string and maybe also an error code ( perhaps an int ), and it could do with it whatever the top level program needs, log it, send it to a dialog box, whatever.
Now this system is quite workable but the costs are higher than they need to be. It is quite likely that many very small data structures will be capable of producing error messages. You may want thousands of these small data structures, ( for example for a linked list link object, or some kind of table entry ) and each one would hold a copy of the same pointer to the error handling function. Also these small objects may be very transient and allocating and deallocating them quickly may be important. It would be a useless waste of cycles to be constantly adding and removing the same tired pointer from every single instance of every single object. In the object view classes described above it is quite likely that one would want many views open at once, that every viewed object has a different view object pointing to it and that only a few views will be open at once. In the error reporting case however, it is likely that there will be only one or a few error reporting functions, and that all the objects will want to use all the very same error reporting functions, say sending all the messages to a dialog box, or to standard error, or all to a log. In the first case having each object have its own pointers to call backs is well worth the cost. In second case it seems like the cost is too high.
Since all the errors will go to a small number of functions it is better
to just store those pointers once in a place all the objects can access.
To do this we make a class very similar to MODEL_VIEW, but where the call-back
pointers are declared 'static':
Now when the top level code initializes its error handling, it needs only to execute the ERROR_DEVICE_STATIC_INIT macro once. On exit it should call the ERROR_DEVICE_STATIC_DESTROY macro. Should the error mechanism change or a new error function come in to use, ( say if error logging were turned on, or the program changed from a text oriented initialization to a graphical user interface ) with a single function call every instance of every object derived from ERROR_DEVICE would report errors the new way. If the programmer fails to call the initialization macro, all the errors would go through 'cerr', as one would expect.
In this implementation the calling code can report errors in one of two
ways. It could either call ReportError() with the error message as an argument,
or if the error message is of a complex format with variables, it could write
its output directly to the 4k text buffer '_ed_buffer', and then call
ReportError() with no arguments:
Now the only drawback to this system is that if for some reason some classes
or some instances of some classes would like to report errors in a different
way than other classes, this simple scheme does not support it. Though
one could imagine a more complex scheme that would; with multiple arrays
of call backs, and tables of objects, where objects would register themselves
on creation, and error reporting functions would register themselves also.
But this seems an overly complex solution for the most common case of wanting
all errors to go to the same 'device'.