Re: Design question involving casting away constness
abhay.burli@gmail.com wrote:
I am told some technical architect has written this code for some sort
of an UMTS class (a fat interface IMHO) with 250+ methods and 50+
members; and i am not supposed to touch it (nor do i fully understand
it in the first place!).
The simlplifed version with the crux of the problem looks like
this ...
// start snip
class A{
public:
void func() { // does some useful calculation }
void func() const { // left blank, notoriously?? }
};
Oh dear! 8(
void doCalc(const A& umtsObjIN) {
// here i need to do some useful calculation via the class
// A's members
}
1. const_cast<A*>(&umtsObjIN)->func();
Note: you can also use "const_cast<A&>(umtsObjIN)", i.e. use a const_cast on
the reference instead of a pointer.
2. ((A)umtsObjIn).func(); // 'C' style
DANGER: this will create a temporary A object, which is surely not what you
want!
3. Make a copy of umtsObjIn into a non-const temporary object and then
invoke the func.
A copyofA = untsObjIN; copyofA.func();
This is extremely weird if it works at all. The point is that I would guess
that this object shows some behaviour, i.e. is not a simple value type.
Assuming the overall quality of the code is similar to what you have shown,
I could imagine the type being copyable according to C++ but that copy will
cause all kinds of weird behaviour.
Options 1 and 2, i think are UB** in C++ because the the object that
is passed as argument is instantiated as 'const A aObj;' during
application initialization. (** casting away constness of an object
which was originally defined as const) or is it O.K.?
No, casting away const from an object that actually is const is UB. Note
however that you are not doing that in option 2, which is equivalent to
option 3 actually.
Suggestions:
1. Write unit tests. These assure that your code works correctly even after
changes.
2. Even if you don't touch the original class, you could write a wrapper
class that replaces the original A class. It would have the same methods
for now and only forward to the wrapped instance.
3. You can now remove the const version of doCalc() in the wrapper class and
try to compile. Every case that you get an error, the code actually called
a method that never did anything, so you _know_ that the call can be
removed without causing any change to the final outcome.
4. If a method is logically 'const' (and if the implementation in A should
be the same), you can add the 'const' and do a const_cast in the
implementation of the wrapper class.
Doing those things will help you better understand what's going on and also
help the compiler tell you what's going on. Further, it will help you
eliminate all calls to the do-nothing versions of functions in a way that
you can prove that it doesn't change anything. Lastly, it gives you the
interface that class A should have had in the first place.
Uli
--
Sator Laser GmbH
Gesch??ftsf??hrer: Thorsten F??cking, Amtsgericht Hamburg HR B62 932
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]