Re: Propogating constness through a const member
Crosbie Fitch wrote:
"Greg Herlihy" <greghe@pacbell.net> wrote in message
news:1149899194.781500.143770@i40g2000cwc.googlegroups.com...
Crosbie Fitch wrote:
const Item& operator=(int i) const { const_cast<Item*>(this)->Assign(i);
Declaring the assignment operator a const method of the class template
"Item" makes the undesirable behavior (that is, assigning a value to a
const Item object) legal. So removing the "const" from the declaration
of operator=() will solve the problem - because assignment then will be
a legal operation for non-const Item objects only.
Unfortunately, that then prevents the assignment u.d0=v.d0, because u.d0 is
const and only non-const assignment operators are available (=(int) and
default assign-copy.)
If you make u.d0 non-const then the default assign-copy will be selected
before =(int), and the default assign copy cannot be overridden and performs
undesired behaviour.
A const assignment operator is a contradiction in terms - a const
object is const precisely because it cannot be assigned a new value.
Therefore, any design that leads to the declaration of a const
assignment operator is a design in serious need of revision.
The problem with the interface above is that it is essentially
implemented in C. Unfortunately, C is not really up to the task of
providing good class interfaces - a fact which no doubt inspired C++.
In other words, programs written C use instance variables and unions
only because the language offers nothing better. But C++ does offer
something better, namely, class methods. Generally, when devising any
kind of interface, it is always a good idea to favor methods over
instance variables. Class methods allow a program to mediate access to
the object's data - that is, methods allow the program to establish
precondtions, post-conditions and invariants.
The natural improvement to make to the current interface is therefore
simply to declare d0 and d1 as class methods instead of as instance
variables. The only change needed in existing client code would be to
add a pair of parentheses wherever d0 and d1 appear in the code - no
other change would be required. For example, instead of writing:
u.d0 = v.d0;
the statement in C++ would be written like this:
u.d0() = v.d0();
This small change in syntax though makes a significant improvement to
the implementation - by eliminating the union nonsense, the clunky
instance variables and the entire business of const objects that are
not really const at all. The C++ interface that does all of this would
look something like this:
class Twin
{
Data twin;
public:
...
int& d0() { return twin.data[0]; }
int d0() const { return twin.data[0]; }
int& d1() { return twin.data[1]; }
int d1() const { return twin.data[1]; }
};
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]