Function overloading: does not compile

C

chrisstankevitz

Q: Why is the compiler not attempting to call the public version of
f()?

class A
{
public:
void f() const {}

private:
void f() {}
};

void g()
{
A a;
a.f(); // error: `void A::f()' is private
}

Thank you,

Chris
 
K

Kai-Uwe Bux

Q: Why is the compiler not attempting to call the public version of
f()?

class A
{
public:
void f() const {}

private:
void f() {}
};

void g()
{
A a;
a.f(); // error: `void A::f()' is private
}

Because the object a has not been declared const.


Best

Kai-Uwe Bux
 
P

peter koch

Q: Why is the compiler not attempting to call the public version of
f()?

class A
{
public:
  void f() const {}

private:
  void f() {}

};

void g()
{
  A a;
  a.f(); // error: `void A::f()' is private

}

Thank you,

Chris

Most likely because you don't understand the lookup-rules in C++.
Lookup is independent of access and thus leads to finding the private
function (your a is not constant). Its not before you have found the
best match that access-rights are checked.

/Peter
 
C

chrisstankevitz

In my particular case, it is clear which function I wanted called. I
wonder why was the standard written such that in this "obvious" case,
the wrong function is called... maybe it would have been too much work
for the compiler developers.

Chris
 
J

jason.cipriani

In my particular case, it is clear which function I wanted called. I
wonder why was the standard written such that in this "obvious" case,

It's equally clear that your code would call the wrong function, since
a is not const. Access rights (public, private, protected) are
independent of name lookup. One thing you could do is this:

class A {
public:
void do_f () const { f(); }
private:
void f () const;
void f ();
};

void g() {
A a;
a.do_f();
}

There you do not need to worry about it. There is only one choice for
do_f(), and that will call the const f() that you want.
the wrong function is called...

Since it is obvious to somebody familiar with the correct rules that
the private non-const version would be called, then it is not the
"wrong" function.
maybe it would have been too much work
for the compiler developers.

This is probably exactly why the rules are the way that they are. I
think that you hit the nail right on the head. said:

Jason
 
P

Paavo Helde

(e-mail address removed) wrote in (e-mail address removed):
In my particular case, it is clear which function I wanted called. I

Yes, it is clear - you declared your object non-const, and then called f()
on it - it is clear you wanted to call the non-const version! Alas, access
rights are biting you; you should add 'friend void g();' to the A class to
get around this :p


More seriously, the keywords are regularity and clarity. The name lookup
rules and access rules are complex enough on their own, no need to make
them more difficult by having some interference between them.

hth
Paavo
 
J

James Kanze

Most likely because you don't understand the lookup-rules in
C++. Lookup is independent of access and thus leads to
finding the private function (your a is not constant). Its not
before you have found the best match that access-rights are
checked.

I've often wondered about this myself. I've never seen them
called anything but "access specifiers". As such, it would seem
obvious to me that they specify access, and not visibility.
(Otherwise, I presume that they would be called visibility
specifiers.) Yet everyone seems surprised when they don't
affect visibility. Why?

(The question here is a bit more complicated, since it also
involves overload resolution. One could imagine overload
resolution excluding functions that can't be called because of
access restrictions, just as it excludes functions which cannot
be called for other reasons. There are good reasons why it
behaves the way it does, but the question is reasonable.)
 
J

James Kanze

In my particular case, it is clear which function I wanted
called. I wonder why was the standard written such that in
this "obvious" case, the wrong function is called... maybe it
would have been too much work for the compiler developers.

In the particular case you posted, it is not at all clear to me
which function you wanted. You called a function on a non-const
object.

More importantly, the standard cannot deal with "particular
cases". It must be expressed in terms of rules that apply
absolutely. In this case, the rule is that access is not
considered during overload resolution. (The main reason for
this is the principle that changes in access should not change
the semantics of a legal program.)
 
J

James Kanze

On Mar 20, 1:32 am, (e-mail address removed) wrote:
This is probably exactly why the rules are the way that they
are. I think that you hit the nail right on the head. <g>

I'm almost sure that that wasn't the reason. It wouldn't be
that difficult to have access play a role in function overload
resolution---there are a lot of things already there that are
far more difficult for the implementers. The real reason, I'm
sure, is that it is a basic principle of C++ that changes in
access cannot change the semantics. They may make a previously
legal program illegal, or vice versa, but they won't silently
cause a legal program to suddenly start doing something
different.

If you think about it, that's really a pretty good thing.
 
J

Jeff Schwab

James said:
I've often wondered about this myself. I've never seen them
called anything but "access specifiers". As such, it would seem
obvious to me that they specify access, and not visibility.
(Otherwise, I presume that they would be called visibility
specifiers.) Yet everyone seems surprised when they don't
affect visibility. Why?

I recall finding the behavior non-obvious, although I definitely find it
a Good Thing now. I don't think the difference between access and
visibility is understood by most new programmers in the first place, so
the term "access specifier" is no more meaningful to them than
"supercalafrajalistic specifier."
(The question here is a bit more complicated, since it also
involves overload resolution. One could imagine overload
resolution excluding functions that can't be called because of
access restrictions, just as it excludes functions which cannot
be called for other reasons. There are good reasons why it
behaves the way it does, but the question is reasonable.)

I would be interested in hearing the other side of that one. Given that
I am happy with the current situation, what would be the motivation for
tying overload resolution to access? Would the OP's example begin to work?
 
A

Alf P. Steinbach

* Jeff Schwab:
I recall finding the behavior non-obvious, although I definitely find it
a Good Thing now. I don't think the difference between access and
visibility is understood by most new programmers in the first place, so
the term "access specifier" is no more meaningful to them than
"supercalafrajalistic specifier."


I would be interested in hearing the other side of that one. Given that
I am happy with the current situation, what would be the motivation for
tying overload resolution to access? Would the OP's example begin to work?

It could support the concept of information hiding. That a derived class
doesn't have to know or care about private parts of a base class. Which is
fairly important, and supported by other languages.

In C++ the only real way to achieve information hiding is to use the PIMPL idiom.

Which drags in several costs -- complexity, physical packaging, efficiency --
when the C++ golden rule is "no unnecessary abstraction cost" (of course,
after the "don't pay for what you don't use" principle, but still). As I recall
the argument for not supporting information hiding in C++ was that it would
require opaque types à la Modula-2, where an opaque type was really just a
pointer in disguise, and this would add an always-there cost for something you'd
not always want to use. But that argument is simply false: information hiding
can be much simpler, because what's important is not physical hiding but
logical, that one shouldn't have to care about, and that one's code shouldn't be
affected by, private things (this also goes to ability to freely change private
things)...


Cheers, & hth.,

- Alf
 
J

James Kanze

* Jeff Schwab:

[...]
It could support the concept of information hiding. That a
derived class doesn't have to know or care about private parts
of a base class. Which is fairly important, and supported by
other languages.

Yes. Although the support does vary.

The problem is that both access control and visibility control
are valid concepts, in themselves. For whatever historical
reasons, C++ choose the first. This means that declaring
something private does NOT mean that clients can ignore it.
Sometimes, in fact, the fact that something is declared private
is actually part of the public interface, e.g. the presence of a
private copy constructor or assignment operator definitely
changes the interface available to the client, and it is common
to declare virtual functions (including pure virtual functions)
private in order to implement programming by contract.

But of course, the fact that we get these benefits means that
there are other benefits we don't get, and as Alf says,
encapsulation takes a serious blow.

Java, I think, mixes them, but private is very definitely
visibility, and not access. The result is, of course, that in
order to implement programming by contract, you have to use
protected virtual functions, rather than private. (Of course,
the real problem is that you can't do this in an interface, only
in an abstract class, which means that you loose multiple
inheritence.)
In C++ the only real way to achieve information hiding is to
use the PIMPL idiom.
Which drags in several costs -- complexity, physical
packaging, efficiency -- when the C++ golden rule is "no
unnecessary abstraction cost" (of course, after the "don't pay
for what you don't use" principle, but still). As I recall
the argument for not supporting information hiding in C++ was
that it would require opaque types à la Modula-2, where an
opaque type was really just a pointer in disguise, and this
would add an always-there cost for something you'd not always
want to use. But that argument is simply false: information
hiding can be much simpler, because what's important is not
physical hiding but logical, that one shouldn't have to care
about, and that one's code shouldn't be affected by, private
things (this also goes to ability to freely change private
things)...

Part of the arguments were related to providing efficent value
semantics with the classical compiler/linker model. Which
resulted in the private parts not being really private; the
compiler at least had to see them and take them into account.
Beyond that, I do seem to recall some argument along the lines
of changing a function from private to public silently changing
semantics (to which, of course, the answer is: don't do that).

What ever the original reasons, it turns out that there is also
some value in access control, as opposed to visibility control.
How much is, as I said, debatable.

I might add that in the case of function overloading, I really
don't think it should matter. Just don't give functions with
different access the same name.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top