[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Simple const * question

Jaco Naude

10/21/2008 10:54:00 AM

Hi

I've been struggling with something that should be very simple to
solve... Basically, I get a const Obj* from a function and I need to
send a pointer to this object to a function accepting only a Obj*. I
get compiler errors as shown below:

source\ManagerViewer.cpp: In member function `void
managerViewer::addLoggerWidget(const QWidget*)':
source\ManagerViewer.cpp:26: error: invalid conversion from `const
QWidget*' to `QWidget*'

I understand that the following will result in a pointer which can be
changed, and the compiler stops:
QWidget* widget = const_widget_ptr;

But the function accepting the pointer is not my own and I need to
send a non-const pointer to it.

Is there a way to work around this?
Thanks in advance
Jaco

9 Answers

Jeff Schwab

10/21/2008 11:08:00 AM

0

Jaco Naude wrote:
> Hi
>
> I've been struggling with something that should be very simple to
> solve... Basically, I get a const Obj* from a function and I need to
> send a pointer to this object to a function accepting only a Obj*. I
> get compiler errors as shown below:
>
> source\ManagerViewer.cpp: In member function `void
> managerViewer::addLoggerWidget(const QWidget*)':
> source\ManagerViewer.cpp:26: error: invalid conversion from `const
> QWidget*' to `QWidget*'
>
> I understand that the following will result in a pointer which can be
> changed, and the compiler stops:
> QWidget* widget = const_widget_ptr;
>
> But the function accepting the pointer is not my own and I need to
> send a non-const pointer to it.
>
> Is there a way to work around this?

It depends. If the function accepting the QWidget* modifies the
addressed widget, it could break reasonable assumptions in other parts
of the code. Welcome to debugging hell.

A common work-around for this problem is to pass a non-const copy (or
clone) of the const object. If you're using the QWidget from Qt,
though, copying isn't an option.

If you're willing to accept the consequences of your actions, try
const_cast: const_cast<QWidget*>(const_widget_ptr).

Sam

10/21/2008 11:24:00 AM

0

Jaco Naude writes:

> Hi
>
> I've been struggling with something that should be very simple to
> solve... Basically, I get a const Obj* from a function and I need to
> send a pointer to this object to a function accepting only a Obj*. I
> get compiler errors as shown below:
>
> source\ManagerViewer.cpp: In member function `void
> managerViewer::addLoggerWidget(const QWidget*)':
> source\ManagerViewer.cpp:26: error: invalid conversion from `const
> QWidget*' to `QWidget*'
>
> I understand that the following will result in a pointer which can be
> changed, and the compiler stops:
> QWidget* widget = const_widget_ptr;
>
> But the function accepting the pointer is not my own and I need to
> send a non-const pointer to it.
>
> Is there a way to work around this?

You can use const_cast<>, however you'll probably wind up with another bug
on your hands. There is a reason why your first function returns a const
pointer, it does not expect the object to be modified. If you go ahead and
have it modified, you'll likely end up with more problems later down the
road.


Andrew Koenig

10/21/2008 3:14:00 PM

0

"Jaco Naude" <naude.jaco@gmail.com> wrote in message
news:2fa82026-fb37-4fe6-8227-4307c80d3c6b@e17g2000hsg.googlegroups.com...

> I've been struggling with something that should be very simple to
> solve... Basically, I get a const Obj* from a function and I need to
> send a pointer to this object to a function accepting only a Obj*.

No you don't. Or at least you don't need to ask advice about how to do it.

If you have a const Obj*, that means you have a pointer to an object that
you have promised not to modify.

If you have a function that accepts only an Obj*, it means that the function
reserves the right to modify the object.

So what you are trying to do is to figure out how to break your promise not
to modify the object. The best advice -- and the only advice I can advocate
until you convince me that it is really important to do otherwise -- is
"Don't do it."


.rhavin grobert

10/21/2008 3:55:00 PM

0

On 21 Okt., 17:14, "Andrew Koenig" <a...@acm.org> wrote:
> "Jaco Naude" <naude.j...@gmail.com> wrote in message
>
> news:2fa82026-fb37-4fe6-8227-4307c80d3c6b@e17g2000hsg.googlegroups.com...
>
> > I've been struggling with something that should be very simple to
> > solve... Basically, I get a  const Obj* from a function and I need to
> > send a pointer to this object to a function accepting only a Obj*.
>
> No you don't.  Or at least you don't need to ask advice about how to do it.
>
> If you have a const Obj*, that means you have a pointer to an object that
> you have promised not to modify.
>
> If you have a function that accepts only an Obj*, it means that the function
> reserves the right to modify the object.
>
> So what you are trying to do is to figure out how to break your promise not
> to modify the object.  The best advice -- and the only advice I can advocate
> until you convince me that it is really important to do otherwise -- is
> "Don't do it."

Guess the following:

int Obj::Read() const;
int Obj::Write(int iWhatever);

int PrettyFunction(int iCommand, Obj* pObject, int iAux)
{
switch(iCommand)
{
case CMD_READ:
return pObject->Read();
case CMD_WRITE:
return pObject->Write(iAux);
default:
DropBombOnWhiteHouse();
}
}

If you have a Obj const* it would still be apropriate to call the
PrettyFunction with the CMD_WRITE by const_cast'ing.

.rhavin grobert

10/21/2008 3:57:00 PM

0

On 21 Okt., 17:55, ".rhavin grobert" <cl...@yahoo.de> wrote:
> On 21 Okt., 17:14, "Andrew Koenig" <a...@acm.org> wrote:
>
>
>
> > "Jaco Naude" <naude.j...@gmail.com> wrote in message
>
> >news:2fa82026-fb37-4fe6-8227-4307c80d3c6b@e17g2000hsg.googlegroups.com...
>
> > > I've been struggling with something that should be very simple to
> > > solve... Basically, I get a  const Obj* from a function and I need to
> > > send a pointer to this object to a function accepting only a Obj*.
>
> > No you don't.  Or at least you don't need to ask advice about how to do it.
>
> > If you have a const Obj*, that means you have a pointer to an object that
> > you have promised not to modify.
>
> > If you have a function that accepts only an Obj*, it means that the function
> > reserves the right to modify the object.
>
> > So what you are trying to do is to figure out how to break your promise not
> > to modify the object.  The best advice -- and the only advice I can advocate
> > until you convince me that it is really important to do otherwise -- is
> > "Don't do it."
>
> Guess the following:
>
> int Obj::Read() const;
> int Obj::Write(int iWhatever);
>
> int PrettyFunction(int iCommand, Obj* pObject, int iAux)
> {
>   switch(iCommand)
>   {
>   case CMD_READ:
>     return pObject->Read();
>   case CMD_WRITE:
>     return pObject->Write(iAux);
>   default:
>     DropBombOnWhiteHouse();
>   }
>
> }
>
> If you have a Obj const* it would still be apropriate to call the
> PrettyFunction with the CMD_WRITE by const_cast'ing.

err, i meant "CMD_READ" and forgot a "return" ;-)

Salt_Peter

10/21/2008 4:41:00 PM

0

On Oct 21, 11:55 am, ".rhavin grobert" <cl...@yahoo.de> wrote:
> On 21 Okt., 17:14, "Andrew Koenig" <a...@acm.org> wrote:
>
>
>
> > "Jaco Naude" <naude.j...@gmail.com> wrote in message
>
> >news:2fa82026-fb37-4fe6-8227-4307c80d3c6b@e17g2000hsg.googlegroups.com...
>
> > > I've been struggling with something that should be very simple to
> > > solve... Basically, I get a const Obj* from a function and I need to
> > > send a pointer to this object to a function accepting only a Obj*.
>
> > No you don't. Or at least you don't need to ask advice about how to do it.
>
> > If you have a const Obj*, that means you have a pointer to an object that
> > you have promised not to modify.
>
> > If you have a function that accepts only an Obj*, it means that the function
> > reserves the right to modify the object.
>
> > So what you are trying to do is to figure out how to break your promise not
> > to modify the object. The best advice -- and the only advice I can advocate
> > until you convince me that it is really important to do otherwise -- is
> > "Don't do it."
>
> Guess the following:
>
> int Obj::Read() const;
> int Obj::Write(int iWhatever);
>
> int PrettyFunction(int iCommand, Obj* pObject, int iAux)
> {
> switch(iCommand)
> {
> case CMD_READ:
> return pObject->Read();
> case CMD_WRITE:
> return pObject->Write(iAux);
> default:
> DropBombOnWhiteHouse();
> }
>
> }
>
> If you have a Obj const* it would still be apropriate to call the
> PrettyFunction with the CMD_WRITE by const_cast'ing.

That you could do it, yes, thats its appropriate, no.
The problem here is you are passing a pointer to a constant and
looking for a way to break a promise.
To drive the point a little further, the parameter Obj* pObject should
really be
Obj* const pObject
where that crucial pointer can't be reseated (or better yet Obj&
r_obj).

If the client of your code sees a constant pointer to a constant (ie:
const Obj* const pObject), the last thing the client will expect is
that the pointee gets modified or reseated. Either would break the
contract and in essence: the interface. At that point your client (who
might very well be yourself in the near future) will then face the
horror of having to read and consult every line of code because the
interface can no longer be trusted.

Victor Bazarov

10/21/2008 4:47:00 PM

0

..rhavin grobert wrote:
> [..]
> Guess the following:
>
> int Obj::Read() const;
> int Obj::Write(int iWhatever);
>
> int PrettyFunction(int iCommand, Obj* pObject, int iAux)
> {
> switch(iCommand)
> {
> case CMD_READ:
> return pObject->Read();
> case CMD_WRITE:
> return pObject->Write(iAux);
> default:
> DropBombOnWhiteHouse();
> }
> }
>
> If you have a Obj const* it would still be apropriate to call the
> PrettyFunction with the CMD_WRITE by const_cast'ing.

The point is to find out *why* in some scope where you've got the
pointer to the const Obj, the object is const, and only then speak about
working around that. 'const_cast' is the last resort. You can only use
it if you're damn sure what you're doing. Without seeing a damn good
argument why this *has* to be done, "do not do it" is the right choice,
and means you need to redesign your software. It's possible that when
you think that you have to call 'PrettyFunction' and all you got is a
const Obj*, you probably should split the 'PrettyFunction' in two. One
would take a const Obj* and the other - a pointer to a regular object.

Without seeing more code it's impossible to pass judgement.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

James Kanze

10/21/2008 10:15:00 PM

0

On Oct 21, 12:53 pm, Jaco Naude <naude.j...@gmail.com> wrote:
> I've been struggling with something that should be very simple
> to solve... Basically, I get a  const Obj* from a function and
> I need to send a pointer to this object to a function
> accepting only a Obj*. I get compiler errors as shown below:

> source\ManagerViewer.cpp: In member function `void
> managerViewer::addLoggerWidget(const QWidget*)':
> source\ManagerViewer.cpp:26: error: invalid conversion from `const
> QWidget*' to `QWidget*'

> I understand that the following will result in a pointer which
> can be changed, and the compiler stops:
> QWidget* widget = const_widget_ptr;

> But the function accepting the pointer is not my own and I
> need to send a non-const pointer to it.

> Is there a way to work around this?

Others have already pointed out many of the issues, but I'll
jump on one additional point. I don't know what QWidgit is, but
from it's name, it sounds like a windowing component. And
normally, there's never any reason to put const on a pointer to
a windowing component. The design error is likely in the
signature of addLoggerWidget, which should take a QWidgit*, and
not a QWidgit const*.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

ytrembla

10/22/2008 9:26:00 AM

0

In article <d95ed2b5-6f83-4e38-962f-01cb95914246@h2g2000hsg.googlegroups.com>,
..rhavin grobert <clqrq@yahoo.de> wrote:
>On 21 Okt., 17:55, ".rhavin grobert" <cl...@yahoo.de> wrote:
>> On 21 Okt., 17:14, "Andrew Koenig" <a...@acm.org> wrote:
>>
>> Guess the following:
>>
>> int Obj::Read() const;
>> int Obj::Write(int iWhatever);
>>
>> int PrettyFunction(int iCommand, Obj* pObject, int iAux)
>> {
>> switch(iCommand)
>> {
>> case CMD_READ:
>> return pObject->Read();
>> case CMD_WRITE:
>> return pObject->Write(iAux);
>> default:
>> DropBombOnWhiteHouse();
>> }
>> }
>>
>> If you have a Obj const* it would still be apropriate to call the
>> PrettyFunction with the CMD_WRITE by const_cast'ing.
>
>err, i meant "CMD_READ" and forgot a "return" ;-)

I'd still say: "No it isn't.". You are breaking encapsulation and
breaking the contract given in the interface.

The interface says:
I take a "Obj *", I may modify it. That's the contract.

You say:
I looked at the implementation of PrettyFunction and as it happens in
that particular version of the implementation if I send CMD_READ as
command, it does not actually modify the Obj *, so in spite of what
the contract says, I'll just pass it an actual constant pointer
const_cast'ed away.

I say:
At some point in the future, someone will modify PrettyFunction. He
will be very careful, have unit tests to ensure that the modification
do not break anything compared to the existing behavior as described
in the contract. The new version of PrettyFunction will modify Obj *
even for the CMD_READ command but that is perfectly legal according to
the contract. The code modification will be tested, reviewed and
included in the package. All perfectly sane and proper. Your code
will then break and you will have a great time trying to figure out
why.

Let me put it otherwise:

You have a cashpoint card (ATM for North American). It has your name
and account number on it and it can be used as a proof of ID (as
const), there's a PIN associated to it which make the cashpoint card
non-const since it allows access to the money in your bank account.

class CashPointCard
{
std::string viewName() const;
int viewAccountNumber() const;
int viewPin(); /// non-const
}

What would you say of:

LendCardAndPinToSalesman(CashPointCard * card, int command)
{
switch(command)
{
case VERIFY_ID:
verify(card->viewName);
case PAY:
withrawMoney(card->viewAccountNumber(), card->viewPin);
}

Will you give your card and pin even if you have observed a salesman
once and to verify id they do not look at the pin?

Or would you rather use:

LendCardNoPinAccessToSalesman(CashPointCard const * card, int command)
{
switch(command)
{
case VERIFY_ID:
verify(card->viewName);
// Can't be done as it would break the contract.
// case PAY:
// withrawMoney(card->viewAccountNumber(), card->viewPin);
}



Yannick