DeMarcus said:
I want to achieve the following.
file_class.cpp
const MessageClass ERROR( "Could not find file" );
class FileClass
{
public:
FileClass()
{
GlobalRegister::register( &ERROR );
}
void open( string s )
{
if( /* Error when opening file */ )
std::cerr << ERROR << std::endl;
}
};
calculation_class.cpp
const MessageClass ERROR( "Could not calculate" );
class CalculationClass
{
public:
CalculationClass()
{
GlobalRegister::register( &ERROR );
}
void calculate()
{
if( /* Error during calculation */ )
std::cerr << ERROR << std::endl;
}
};
I want to allow any file be able to use the symbol ERROR but at the
same time they shall be able to register the pointer to that variable
without clashing with other variables with the same symbol name.
I have looked over the skeleton code that you have provided here and,
rather than it assisting me in thinking about how to best get around the
problems of multiply-defined ERROR instances, I cannot escape feeling
uneasy about the whole design. I am wondering if the very appearance of
the specific problems that you are facing here are not symptomatic of a
design that is otherwise flawed at a very fundamental level. Specific
questions that jump to mind without resolution (for me) and which lead
me to this through include the following:
1. What is the necessity in the first place of instantiating an
instance of an error message and then `registering' it by address?
Why is it not the responsibility of the GlobalRegister itself to
manage its own error messages - i.e., /contain/ them?
2. Why do you give the responsibility to each specific class -
FileClass, CalculationClass - for registering their respective error
messages? Why isn't the initialization of all such error messages
achieved at a single point of initialization at program startup?
I ask this, as it derives from the next question:
3. Why is it that each ERROR gets registered *every* time that an
instance of the relevant class is instantiated when all the
registration achieves is to add the *same* address to the *same*
object to the registry over and over again? Essentially, on
attempting to open 100 files or perform 1000 calculations, what is
the purpose of the registry holding 100/1000 pointers to the same
single ERROR instance?
4. What is the purpose of registering in the first place, when you
do not then make use of the registry to retrieve the appropriate
error message in, for example, FileClass:
pen(string) and
CalculationClass::calculate()? Instead, you short circuit the
registry (in effect) and make use of the TU-local ERROR instance
directly (and I would suggest that it is only because of this
avoidance of the registry at this point that you suppose that the
presence of these TU-local ERROR instances contributes to your
design.)
Without, clearly, having a full sense of the wider program this code
applies to - for instance, I only have a vague idea from other posts of
yours what the registry's purpose is - I nevertheless feel that some
other design effort is required in order to centralise responsibilities
where they belong and, in particular, to give to the registry full
handling of the objects that you are registering with it; then, it is
for the program code to *use* that registry.
With a design broadly along these lines you will find there shall be no
need for any ERROR objects outside of the registry, no necessity of them
being similarly named and requiring special handling to avoid name
clashes, and that the system as a whole will be better balanced in terms
of design. It will also be more readily extensible.
As an idea, I would suggest that you at least consider the following as
alternatives to your present design:
1. Let your `registry' be a full-fledged registry in the sense that
it alone is responsible for managing the objects registered with it
(i.e., let them not have an existence /outside/ of the registry
itself);
2. Let all interaction with the registered objects (error messages
here) be through the interface of the registry;
3. Let all such objects required by your program be registered in a
single place during program startup, unless (which your example code
doesn't indicate is the case) the error messages contain more
detailed information about the /specific/ context in which a
particular error has occurred.
And finally, consider whether you need the registry at all. From other
posts I am gathering that it's purpose is to enable appropriate error
messages to be output in an appropriate language. Is this not the
domain of std::locale? Why not just have appropriate error messages
raised where required and have your MessageClass respond, in terms of
what it actually outputs, according to the locale of the program user.
Again, it's about responsibilities. It seems fair to argue that it is
the responsibility of a MessageClass to be locale aware, itself, in this
sense.
Regards
Paul Bibbings