const version of a function w/o copy/paste


G

Gernot Frisch

Hi,

// how can I
const int* GetPInt()const
{
return (const int*)the_non_const_function_using_the_same_name();
}

thank you.
-Gernot
 
Ad

Advertisements

V

Victor Bazarov

// how can I
const int* GetPInt()const
{
return (const int*)the_non_const_function_using_the_same_name();
}

You could do

return const_cast<YourType*>(this)->GetPInt();

but beware of UB. The use of const_cast is only defined *if* you know
for sure that the object is non-const. If you don't, it's UB.

Now, let me ask you, why do you have two versions of the same function?
If they do exactly same thing (and do not change the state of the
object), then drop the non-const one. If they *don't* do the exactly
same thing, then you have no business calling a non-const member from a
const member.

V
 
G

Gernot Frisch

Now, let me ask you, why do you have two versions of the same function?

I access members through a pointer. Now, the object can be a const pointer, thus I only get a const pointer to the child and
vice versa:

class child;
class parent
{
child* GetChild() {return &m_child;}
const child* GetChild()const {return &m_child;} // for when parent prt is const
};

thanks for the const cast hint.
 
V

Victor Bazarov

I access members through a pointer.

That's rather odd. Shouldn't it be a reference?
> Now, the object can be a const
pointer, thus I only get a const pointer to the child and vice versa:

class child;
class parent
{
child* GetChild() {return &m_child;}
const child* GetChild()const {return &m_child;} // for when parent prt
is const
};

thanks for the const cast hint.

It is *better* to have two accessors like you've shown here, than go
through the complexity of "forwarding" from the const accessor to the
non-const one. Cleaner.

V
 
V

Victor Bazarov

Gernot said:
Hi,

// how can I
const int* GetPInt()const
{
return (const int*)the_non_const_function_using_the_same_name();
}

thank you.
-Gernot

You should do it the other way round - call the const version from the
non-const one.[..]

+1

V
 
J

James Kanze

On 7/22/2010 8:33 AM, Gernot Frisch wrote:
You could do
return const_cast<YourType*>(this)->GetPInt();
but beware of UB. The use of const_cast is only defined *if*
you know for sure that the object is non-const. If you don't,
it's UB.

No. It's only UB if you actually attempt to modify a const
object.

Still, I'd prefer the inverse, calling the const function from
within the non-const one, then casting away const on the results
(since you know that you're not really const there).
Now, let me ask you, why do you have two versions of the same
function?
If they do exactly same thing (and do not change the state of
the object), then drop the non-const one.

The two functions have different return types. Both in fact do
exactly the same thing, but the return value of one allows
client code to modify the object; the return type of the other
doesn't.

This is a standard idiom for container classes (where GetPInt is
named operator[], and returns a reference rather than a pointer).
 
Ad

Advertisements

B

Bo Persson

Stuart said:
Presumably the non-const one returns int*, so clients can change
something in the object through that, but only if the object itself
is non-const. If the object's const, you want to return a const
int* to the same thing. Whether or not the class should be exposing
its internal data like this at all depends on the context I guess.

It's evidently "evil" to call a non-const member from a const one,
but I was under the impression that there's nothing particularly
evil about doing it the other way round - in fact, I thought it was
almost
idiomatic if you need to provide both a non-const and const
accessor? It's certainly better than duplicating the code, which is
the
alternative...

It surely depends on what the functions do. The one returning an int*
to class member will likely be

int* getbuffer()
{ return &buffer; }

const int* getbuffer() const
{ return &buffer; }


How much duplication can you save here?


Bo Persson
 
S

Stuart Redmann

Hi,

// how can I
const int* GetPInt()const
{
    return (const int*)the_non_const_function_using_the_same_name();

}

We had a similar topic quite recently (http://groups.google.de/group/
comp.lang.c++/browse_frm/thread/7943a399a96324bf#), and came up with
the following class:


// Wrapper for plain pointers that behaves as const-correct
// accessor.
template<class t_Class>
class ConstCorrectAccessor
{
t_Class* m_InternalPointer;
public:
ConstCorrectAccessor (t_Class* Pointer)
: m_InternalPointer (Pointer)
{}


// Accessor methods with const-correct overload.
const t_Class* operator-> () const {return m_InternalPointer;}
t_Class* operator ->() {return m_InternalPointer;}



};


class SomeClass
{
public:
void foo () const {}
void bar () {}


};


class AnotherClass
{
public:
ConstCorrectAccessor<SomeClass> SomeObject;
public:
AnotherClass (SomeClass* Object)
: SomeObject (Object)
{}

void foo () const
{
SomeObject->foo (); // OK
SomeObject->bar (); // Error: Non-const method on SomeObject.
}



};


int main ()
{
SomeClass a;
const AnotherClass b (&a);
b.SomeObject->foo (); // OK
b.SomeObject->bar (); // Compilation error: b is const

AnotherClass c (&a);
c.SomeObject->foo (); // OK
c.SomeObject->bar (); // OK: c is not const



}


Regards,
Stuart
 
Ad

Advertisements

G

Gernot Frisch

Yes, unless the accessor does something non-trivial, in which case it's (arguably) better not to duplicate the code (less to
maintain). As an example I've managed to dig up:

int& SliceLocation::eek:perator[](SliceOrientation ori)
{
return const_cast<int&>(const_cast<const SliceLocation*>(this)->operator[](ori));
}


Excellent. That was exaclty the reason why I asked this question.
 

Top