 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
George Ryan Guest
|
Posted: Fri Aug 13, 2004 2:33 pm Post subject: NVI Idiom and Invariants |
|
|
Hello,
I have posted some code below that shows using the NVI idiom to more
cleanly have virtual behaviour within an inherited interface. However,
I have run into a problem I don't know how to solve in relation to
inheriting the invariants. I would like to weaken the precondition,
but the add() function in the base class is the entity actually
applying the precondition, so I don't have the ability to short circut
it as I want to.
I've considered:
1. Moving the pre and post conditions into the do_add() function. This
means that everyone inheriting the class would be on their honour to
call the pre and post conditions, in addition to any others they may
add.
2. Making the pre and post condition functions virtual as well, but
this just seems like a variant of #1, providing an opportunity for the
user to mistakenly mess up the invariant checking by forcing them to
rewrite the original.
Can anyone suggest a good/better way to handle this condition? Are
invariants orthogonal to the inheritence model in C++?
Thank you,
George
---- START ----
class invariant {
public:
void add( const int& i )
{
precondition( i );
do_add( i );
postcondition( i );
}
protected:
virtual void do_add( const int& i )
{
try {
list_.push_back( i );
}
catch ( const std::exception& e )
{
// some sort of error must have occured.
}
}
// Precondition: i must not already be in the list
void precondition( const int& i )
{
if ( find( list_.begin(), list_.end(), i ) != list_.end() ) {
throw 0;
}
}
// Postcondition: i must be in the list
void postcondition( const int& i )
{
if ( find( list_.begin(), list_.end(), i ) == list_.end() ) {
throw 0;
}
}
list<int> list_;
};
class inherited : public invariant {
protected:
// Would like to weaken the precondition here
// so that an exception is _not_ thrown when
// i is already in the list, just no-op.
virtual void do_add( const int& i )
{
// Would LIKE to simply return if i is already in
// the list, but I can't because precondition() has
// already been called.
// do a bunch of other stuff or add
// i to list another way
}
};
---- END ----
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Tokyo Tomy Guest
|
Posted: Mon Aug 16, 2004 2:51 pm Post subject: Re: NVI Idiom and Invariants |
|
|
[email]gwryan (AT) accesswave (DOT) ca[/email] (George Ryan) wrote in message news:<d871bbf3.0408121529.115a7ec9 (AT) posting (DOT) google.com>...
| Quote: | Hello,
I have posted some code below that shows using the NVI idiom to more
cleanly have virtual behaviour within an inherited interface. However,
I have run into a problem I don't know how to solve in relation to
inheriting the invariants. I would like to weaken the precondition,
but the add() function in the base class is the entity actually
applying the precondition, so I don't have the ability to short circut
it as I want to.
I've considered:
1. Moving the pre and post conditions into the do_add() function. This
means that everyone inheriting the class would be on their honour to
call the pre and post conditions, in addition to any others they may
add.
2. Making the pre and post condition functions virtual as well, but
this just seems like a variant of #1, providing an opportunity for the
user to mistakenly mess up the invariant checking by forcing them to
rewrite the original.
Can anyone suggest a good/better way to handle this condition? Are
invariants orthogonal to the inheritence model in C++?
...
|
If you only do not want to populate a container with same elements,
please use set instead of list. If you want to do something when you
find an specific element in a list, you have to write more codes.
Given that the NVI idiom and pre- and post- conditions are suitable
for your application, let me advise you not to use "throw" to control
program flow, since it is recognized as an error reporting mechanism.
The simplest way used from age of C is a flag for place of "throw". If
the pre-condition find an specific element, it sets the flag true. The
do-add check the flag, and if the flag is true, do something. The
invariant could have the flag as a protected data member.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Mon Aug 16, 2004 7:42 pm Post subject: Re: NVI Idiom and Invariants |
|
|
[email]gwryan (AT) accesswave (DOT) ca[/email] (George Ryan) wrote in message
news:<d871bbf3.0408121529.115a7ec9 (AT) posting (DOT) google.com>...
| Quote: | I have posted some code below that shows using the NVI idiom to more
cleanly have virtual behaviour within an inherited interface. However,
I have run into a problem I don't know how to solve in relation to
inheriting the invariants. I would like to weaken the precondition,
but the add() function in the base class is the entity actually
applying the precondition, so I don't have the ability to short circut
it as I want to.
|
That's actually fairly simple. Just define a public add function in the
derived class, with the weakened preconditions.
Note that if the user calls through a pointer or a reference to the base
class, he still gets the base class preconditions. I know that the
classical programming by contract idiom says that he should not, but I'm
not convinced that this is right. If, as a user, I am programming
against a Base interface, and I mess up, I want to know about it. Even
if, by chance, the actual object happens to be a Derived in my
particular test case. If I know that in fact, in this location, I
actually have a Derived, I will start by saying so, e.g. with a
dynamic_cast.
In the end, the pre- and post conditions are part of the interface. If I
am using the Base interface, then that is my contract, and my code
should strictly adhere to that contract. If I know that in fact, I have
a derived, and I want to use the Derived interface, then I should say so
explicitly. In particular, if the user function is called with a pointer
to base, and wants to use it as a Derived (e.g. with the weakened
pre-conditions), then the fact that the dynamic type is actually a
derived is part of its precondition, e.g.:
void someClientFnc( Base* pBase )
{
Derived* pDerived = dynamic_cast< Derived* >( pBase ) ;
PRECONDITION_CHECK( pDerived != NULL ) ;
pDerived->add() ;
}
Alternatively, the client code is doing some conditional tests before,
and only depends on the weakened precondition in an if block. Again,
however, a dynamic_cast permits verifying that his logic in the
conditional tests is correct.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
John Sheehan Guest
|
Posted: Tue Aug 17, 2004 10:05 pm Post subject: Re: NVI Idiom and Invariants |
|
|
I think the reason you are running into problems is because you are
trying to weaken the precondition. Given your design, that is not
really possible. You have a couple of options:
1.) As you mentioned, you could make the pre / post conditions
virtual. This would allow you to override either one's functionality,
if desired. This would allow you to strengthen or weaken the pre /
post conditions as needed. I'm not a big fan of this, as your base
class is serving multiple purposes, namely defining the calling
template as well as one default implementation. I'm not sure these
particular pre / post conditions deserve the special status, but maybe
they do for your application.
2.) Define a template that accepts the pre / post coditions as well
as the actual worker class. This has the advantage of keeping
separate choices orthogonal. You could then define a bunch of
different pre / post conditions that you could choose from, depending
upon your needs. You could also design it so that it ends up defining
a separate base type, depending upon the combination of pre / post
conditions chosen. I think this is a good idea, since the code that
is using the actual implementation should be written knowing what the
invariants are. Changing those invariants through some form of
virtual function implementation runs the risk of breaking the client
code.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|