The following code snippet shows that VC++ 7.1 correctly compiles a static member function invocation from an Unrelated class, since this static member function is public. I expected to compile the same invocation from a DistantlyRelated class. What actually happened was that the compiler produced:
error C2247: 'A::function' not accessible because 'CloselyRelated' uses 'private' to inherit from 'A'
I'm guessing that the above compiler error message may be caused by too-aggressive "compiler conformance work". If A::function() were not static, a compiler error would be appropriate, because the compiler would need to supply an implicit object reference. But no object reference is needed, since function() is static.
struct A {
static void function() {}
};
class Unrelated {
void f() {A::function();} // Compiles fine, as expected.
};
class CloselyRelated : private A {
void f() {A::function();}
};
class DistantlyRelated : public CloselyRelated {
void g() {A::function();} // Unexpectedly causes error C2247
};
Is this in fact an compiler bug? If so, is it already known to Microsoft?
Bill Rubin 6 4335
"Bill Rubin" <an*******@discussions.microsoft.com> wrote in message
news:2F**********************************@microsof t.com... The following code snippet shows that VC++ 7.1 correctly compiles a static
member function invocation from an Unrelated class, since this static member
function is public. I expected to compile the same invocation from a
DistantlyRelated class. What actually happened was that the compiler
produced: error C2247: 'A::function' not accessible because 'CloselyRelated'
uses 'private' to inherit from 'A' I'm guessing that the above compiler error message may be caused by
too-aggressive "compiler conformance work". If A::function() were not
static, a compiler error would be appropriate, because the compiler would
need to supply an implicit object reference. But no object reference is
needed, since function() is static. struct A { static void function() {} };
class Unrelated { void f() {A::function();} // Compiles fine, as expected. };
class CloselyRelated : private A { void f() {A::function();} };
class DistantlyRelated : public CloselyRelated { void g() {A::function();} // Unexpectedly causes error C2247 };
Is this in fact an compiler bug? If so, is it already known to Microsoft?
This is not a compiler bug. It's the way the language is
designed to work. When you use private inheritance, you're
saying that the private base class is part of the
implementation -- not part of the interface -- of the
derived class. Essentially, it means that the public members
of the base class become private members of the derived class.
In other words, the effect in your example is like
class CloselyRelated {
private:
static void function();
};
class DistantlyRelated : public CloselyRelated {
void g() { function(); // error: private
}
};
This has nothing to do with the fact that "function" is static.
Access is primarily based on names. If "A" defined a typedef or
an enumeration constant, "DistantlyRelated" wouldn't be able to
use those, either. You can't use anything in "A" because
"CloselyRelated" has effectively closed the gate by using
private inheritance.
-- William M. Miller
The MathWorks, Inc.
Thanks very much for your helpful response. However, I'm still uncertain about your explanation. If "A" defined a typedef or an enumeration constant, "DistantlyRelated" wouldn't be able to use those either.
I tried that in VC++ 7.1, and you're half right: An enum causes the same error, as you predict. But a typedef is accepted just fine. Is this a compiler bug? At best, the behavior seems inconsistent
I'm confused about which principle should govern. Paraphrasing Stroustrup, Section 15.3
1. The name of a public member of a class can be used by any function
2. Access control is applied uniformly to names. What a name refers to does not affect the control of its use
Principle 2 is essentially what you're saying. If this governs, then it seems to me that Principle 1 -- the first principle of access control -- must be qualified to say something like " ... unless the function is in a distantly related scope ...", a rather unwieldy principle! Am I missing something here? On the other hand, consider Stroustrup, Section 5.3.2
3. The access specifier for a base class controls ... the conversion of pointers and references from the derived class type to the base class type. Only friends and members of a derived class can convert a derived class ptr/ref to a ptr/ref of a private base class
My understanding has been that Principle 3 is the essence of access to private base class members. Applying Principle 3 to my example, non-static member functions and data members of "A" would be inacessible to DistantlyRelated, not because they "essentially ... become private members of CloselyRelated" (a transformation I haven't been able to find justification for), but because DistantlyRelated cannot convert its "this" pointer to an "A*"
As I see it, Principle 2 does not apply to inheritance because inheritance-related access restrictions are not governed by names, but by "this" pointer up-conversions. If my understanding is correct, we can now apply an unmodified Principle 1 to my example, showing that public members of "A" other than non-static member functions and data members (typedefs, enums, static members, embedded classes) should be accessible in DistantlyRelated, as I'd first thought
Bill Rubin
I'd be most interested if someone could post to this thread to help resolve the conflict between the two posts (Miller's and mine) of 2/5. Is Miller's analysis (post on 2/5) correct? If so
Q1: Does that mean that the rule "The name of a public member of a class can be used by any function" is not always correct
Q2: What is the flaw in my analysis
Q3: Is VC++ 7.1's acceptance of a distantly-related typedef a compiler bug
Bill Rubin
Bill Rubin wrote: Thanks very much for your helpful response. However, I'm still uncertain about your explanation.
If "A" defined a typedef or an enumeration constant, "DistantlyRelated" wouldn't be able to use those either. I tried that in VC++ 7.1, and you're half right: An enum causes the same error, as you predict. But a typedef is accepted just fine. Is this a compiler bug? At best, the behavior seems inconsistent.
That's a bug - the typedef shouldn't be accessible. I'm confused about which principle should govern. Paraphrasing Stroustrup, Section 15.3:
1. The name of a public member of a class can be used by any function.
2. Access control is applied uniformly to names. What a name refers to does not affect the control of its use.
Principle 2 is essentially what you're saying. If this governs, then it seems to me that Principle 1 -- the first principle of access control -- must be qualified to say something like " ... unless the function is in a distantly related scope ...", a rather unwieldy principle! Am I missing something here? On the other hand, consider Stroustrup, Section 5.3.2:
You're missing something.
In C++ there are a couple of things that interact to determine how a name is
resolved when it's referenced inside a class member.
1. Names defined in derived classes hide definitions of the same name in the
base class.
2. Access control is applied after name lookup in all cases.
So in your original example, since 'function' is not (re-)defined in
CloselyRelated, it's definition from A is visible in DistantlyRelated.
Since CloselyRelated privately inherits from A, the names in A are
inaccessible in DistantlyRelated. Note that visibility and accessibility
are separate concerns and do not interact. 3. The access specifier for a base class controls ... the conversion of pointers and references from the derived class type to the base class type. Only friends and members of a derived class can convert a derived class ptr/ref to a ptr/ref of a private base class.
This is in effect another way of stating the same thing when applied to
access of non-static, non-type members of a class from within a member
function of a derived class. It also applies outside the class: A client
cannot assign a CloselyRelated* value to an A* variable due to the private
inheritance. My understanding has been that Principle 3 is the essence of access to private base class members. Applying Principle 3 to my example, non-static member functions and data members of "A" would be inacessible to DistantlyRelated, not because they "essentially ... become private members of CloselyRelated" (a transformation I haven't been able to find justification for), but because DistantlyRelated cannot convert its "this" pointer to an "A*".
That would be true if this pointer conversion was the only thing involved -
it's not. Private inheritance means that the names are not accessible. It
also means that the corresponding this pointer conversion is illegal. As I see it, Principle 2 does not apply to inheritance because inheritance-related access restrictions are not governed by names, but by "this" pointer up-conversions. If my understanding is correct, we can now apply an unmodified Principle 1 to my example, showing that public members of "A" other than non-static member functions and data members (typedefs, enums, static members, embedded classes) should be accessible in DistantlyRelated, as I'd first thought.
HTH
-cd
Thanks very much, Carl, for helping to explain the situation and confirm Miller's post. (Your post must have crossed with mine earlier today.)
So public members of a class "A" will be hidden from a DistantlyRelated class without regard to whether an object reference is needed to use them. I'm surprised!
In my code, I worked around my compilation problem using the following ugly hack: As a supplementary part of A's effective interface, I define a global forwarding function
inline void functionInA() {A::function();}
Then, in place o
void DistantlyRelated::g() {A::function();} // error -- does not compil
I writ
void DistantlyRelated::g() {functionInA();}
which accomplishes what I intended. To summarize, one can invoke "A::function()" in unrelated and closely related code, but in distantly related code one must use the hack "functionInA()".
I think I'd feel better about this if I understood why this aspect of the C++ language makes more sense than my (apparently wrong) analysis
Bill Rubin
"Bill Rubin" <an*******@discussions.microsoft.com> wrote in message
news:1D**********************************@microsof t.com... Thanks very much for your helpful response. However, I'm still uncertain
about your explanation.
Sorry I was away from the newsgroup for a while and wasn't able to
respond in a timely fashion. Carl's answers are correct; I'll just
take a slightly different route to the same result. If "A" defined a typedef or an enumeration constant, "DistantlyRelated"
wouldn't be able to use those either. I tried that in VC++ 7.1, and you're half right: An enum causes the same
error, as you predict. But a typedef is accepted just fine. Is this a
compiler bug? At best, the behavior seems inconsistent.
It's a bug.
I'm confused about which principle should govern. Paraphrasing
Stroustrup, Section 15.3: 1. The name of a public member of a class can be used by any function.
2. Access control is applied uniformly to names. What a name refers to
does not affect the control of its use. Principle 2 is essentially what you're saying. If this governs, then it
seems to me that Principle 1 -- the first principle of access control --
must be qualified to say something like " ... unless the function is in a
distantly related scope ...", a rather unwieldy principle! Am I missing
something here? On the other hand, consider Stroustrup, Section 5.3.2:
Yes. The thing you're missing is that _how_ the name is found is
also important. (Let me preface this by saying that what I'm
describing is how the language is defined, not what is currently
implemented in the 7.1 compiler. VC++ 7.1 is much closer to
Standard C++ than 6.0 was, but it's still not quite there yet.
You can try these out using www.comeaucomputing.com/tryitout and
get the right answer, though.)
The key factor in all of this, as I mentioned in my earlier post,
is the following citation from the C++ Standard (11.2 para 1):
If a class is declared to be a base class (clause 10) for
another class using the public access specifier, the public
members of the base class are accessible as public members of
the derived class and protected members of the base class are
accessible as protected members of the derived class. If a
class is declared to be a base class for another class using
the protected access specifier, the public and protected
members of the base class are accessible as protected members
of the derived class. If a class is declared to be a base
class for another class using the private access specifier, the
public and protected members of the base class are accessible
as private members of the derived class. [Footnote: As
specified previously in clause 11, private members of a base
class remain inaccessible even to derived classes unless
friend declarations within the base class declaration are used
to grant access explicitly.]
There are three different ways you can name A::function when you
call it from DistantlyRelated::g(), and each has different effects
with respect to accessibility:
1) If you use no qualification (just "function()"), the name
"function" is a public member of A and thus a private member of
CloselyRelated, and thus not accessible (as described in the
footnote quoted above) from DistantlyRelated.
2) Now consider the case you gave, "A::function()". There are
two rules that affect this analysis. First, the access of a
name is considered relative to its "naming class" (i.e., the
class in which the name is looked up). In this case, that's
"A" -- "A::function" means "look up 'function' in class 'A'".
"function" is public when named in "A", so that part works out
fine.
The second rule has to do with something called "class name
injection" -- the name of a class is "injected" into the class for
lookup purposes. (To keep this relatively short, I won't discuss
the reasons for this here, but if you're really curious, ask and
I'll go into it.) This means that when you say "A" in
DistantlyRelated, you're really finding the "A" that's a member of
the "A" class -- and _it's_ inaccessible, for the same reason an
unqualified reference to "function" is. The upshot is that, even
though "function" is public when named in "A", the reference
"A::function" still fails the access check because "A" isn't
accessible.
3) The third way to write this reference is "::A::function" --
and that works. The reason is that it doesn't fall afoul of
either of the two preceding problems: "::A" is accessible, because
"::A" refers to the name of the class in global scope, where no
access applies, rather than the injected name that's a member of
the class "A", and (as I mentioned) "function" is public when
named in "A".
Unfortunately, this won't help you with your program, because
VC++ 7.1 either hasn't implemented class name injection or hasn't
gotten it right, I'm not sure which; "::A::function" fails the same
way that "A::function" does. (Most compilers that haven't yet
implemented class name injection fail by accepting _both_
"A::function" [incorrectly] and "::A::function", which is why I'm
not quite sure about VC++ 7.1.) However, I thought it might be
helpful to explain the theory behind what _should_ be happening and
then relate it to what you're actually seeing.
3. The access specifier for a base class controls ... the conversion of
pointers and references from the derived class type to the base class type.
Only friends and members of a derived class can convert a derived class
ptr/ref to a ptr/ref of a private base class. My understanding has been that Principle 3 is the essence of access to
private base class members. Applying Principle 3 to my example, non-static
member functions and data members of "A" would be inacessible to
DistantlyRelated, not because they "essentially ... become private members
of CloselyRelated" (a transformation I haven't been able to find
justification for), but because DistantlyRelated cannot convert its "this"
pointer to an "A*".
Actually, your #3 is parallel to the access control of names. In
order to call a nonstatic member function, the name must be accessible
_and_ the object or pointer you use must be convertible to the class
of the member function. The call is invalid if either of these
conditions fails.
-- William M. Miller
The MathWorks, Inc. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: WSeeger |
last post by:
When creating a new class, is it encouraged to always include error
handling routines within your LET and GET procedures? It's seems that
most text books never seem to include much about error...
|
by: Holly |
last post by:
Hello List,
My windows laptop configured as: XP, Python 1.5.2, MySQL 4.0.9 and
Appache 1.3.17
A form ("Post" has been used) has a product list with about 400
products. The user checks each...
|
by: |
last post by:
I am accessing the same error-containing ASP page on an ISP server using w2k
IE6 but with different effect.
On the first computer I get several line of HTML outputed by ASP, shown
correctly by...
|
by: p |
last post by:
WE had a Crystal 8 WebApp using vs 2002 which we upgraded to VS2003. I also
have Crystal 9 pro on my development machine. The web app runs fine on my
dev machine but am having problems deploying....
|
by: Manuel |
last post by:
I'm trying to compile glut 3.7.6 (dowbloaded from official site)using
devc++.
So I've imported the glut32.dsp into devc++, included manually some
headers, and start to compile.
It return a very...
|
by: bazzer |
last post by:
hey,
im trying to access a microsoft access database from an ASP.NET web
application in visual basic 2003.NET. i get the following error when i
try running it:
Server Error in...
|
by: Deepath G |
last post by:
This is deepath..
I am getting some linker error when i am trying to connect Websphere MQ using Borland C++ Builder 2006 using imqi.hpp on windows.
Error Message
-----------------------
...
|
by: .nLL |
last post by:
Erorr is
---------------------
Microsoft VBScript runtime error '800a0046'
Permission denied
/a.asp, line 3
-----------------------
|
by: khalidanwar123 |
last post by:
i am getting the following error while updating a clob field.
ERROR java.sql.SQLException: Data size bigger than max size forthis type: 4003
19:28:27,499 ERROR at...
|
by: madhu.ab |
last post by:
Hi All,
I am getting the following errors when i am including header file
winuser.h
I dont know whats happening. How will an error occur in winuser.h??
Please help.
\microsoft visual...
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: Aliciasmith |
last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
|
by: tracyyun |
last post by:
Hello everyone,
I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
|
by: NeoPa |
last post by:
Introduction
For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM)
Please note that the UK and Europe revert to winter time on...
|
by: nia12 |
last post by:
Hi there,
I am very new to Access so apologies if any of this is obvious/not clear.
I am creating a data collection tool for health care employees to complete. It consists of a number of...
|
by: NeoPa |
last post by:
Introduction
For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
|
by: isladogs |
last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, Mike...
| |