Topic: Ambiguity with Operator::
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Thu, 22 Oct 92 23:28:03 GMT Raw View
Several weeks ago, I posted a message on the ambiguity problem
with operator::, but receives no response. I'd like to post some
discussion with Mr. Stroustrup on this issue (I apologize here
if it is not suitable) The key issue is that wthether a
modification is necessary. If not, what is the clarification
in the standard?
***> However, we have - I think - reached the real problem.
A base is referred to as an unnamed member of a class yet
we use the name of its class to refer to the sub-object
representing it. Had a base B been defined as a member
named B there would have been no problem. As it is, we
can define both a base of class B and a member called B
and need to resolve the potential ambiguity.
Yes, that's exactly what I want to say.
***> As you saw, C++ resolves it in favor of the member - and you
can't explicitly refer to members of the base class without
some workaround.
I'm not sure, since I cannot find any supporting statement in any
C++ document. Just look at what some C++ compilers say on this
example:
class A { public: static int i; };
class A_ { public: static int i; };
class B: public A { public: static A_ A; };
B b;
B::A::i =100;
b.A::i =100;
BORLAND C++3.1 issues an error message: Type qualifier 'A' must
be a struct or class name. Therefoer BC++3.1. resolves it in favor
of member just as you mentioned:
***> In B's scope look for the name A. That A is the static
variable A. Thus B::A::i is the i of B's static member A.
However, one cannot apply :: to an object so A::i is an
error.
However, in expression "b.A::i", I don't think C++ will resolve
A::i in favor of member.
On the contrary, Microsoft C/C++7.0 resolves "B::A::i" in favor of
base class: "B::A::i=100" makes A::i==100. However, for nested
classes, Microsoft C/C++7.0 resolves it in favor of the member:
class A { public: class NA {}; };
class B: public A
{ public:
class A { public: class NA{}; };
};
"B::A::NA" is B's member A's member NA.
Quite confused, right?
***> I don't think a solution is necessary. The current rules are
consistent and coherent. They may, however, not be stated
explicitly enough. Hence the copy to Jonathan.
I agree. As long as a clear statement is made for resolving the
armbiguity, there is no problem with C++. We can always find the
way to work around if we need to resolve menbers defined in base.
For example, if we really need class A's member NA, we can always
use "A::NA", and we need not prefix it with class B.
***> On the other hand, should the issue be opened I'd (with the
benefit of a few extra years of experience) argue that the
name of a base class should double as the name of the sub-object
representing it thus making it illegal to have both a base
class and a member with the same name.
The real problem is not the name confusion. Yes, we can disallow the
name of a member be the same as a base name. The problem is the
semantic armbiguity of operator "::", its meaning depends on what is
the followed and what is the following. For example,
b.A::i // scope resolute, resolve in favor of base
B::A::i // member selector, resolve in favor of member by BC++
// scope resolute, resolve in favor of base by MS C/C++
B::A::NA // member selector, resolve in favor of member
When operator"::" appears in a more complex expression, I bet the
programmer will be lost at sea.
My original post:
_____________________________________________________________________
[The Problem]
Two kinds of meaning are associated with operator "::" in the
current C++:
(1) "::" as a selection operator:
class::name // name is a component of the class.
This expression is commonly used in accessing a nested class and
a static member.
Example1:
class A { public: static int i; };
int i = A::i;
Note that a static member can also be accessed through an object,
Therefore, "i" can be viewed as a member either of a class or
of an instance of this class.
Example2:
class A { public: class B {}; };
A::B ab;
where "A::B" means that "B" is a component class of class "A".
(2) "::" as a scope resolution operator:
::name // name is defined in global scope
class::name // name is defined in this class or its super
Example1:
class A { public: int i; };
class B: public A { public: int i; };
B b;
b.A::i;
where "A::i" suggests that "i" is defined in class "A",
but "i" is not the component of "A", instead, it is the member
of object "b". Therefore, in expression "b.A::i", the selector of
"i" is "b" and "A" is only the scope resolute of "i".
Example2:
class A { public: void foo (); };
void A::foo () {...};
where "A::foo" suggest "foo" is defined in class "A" ( Note that
"foo" is not the member of class "A", it belongs to an instance
of class A).
The problem is that we can not always distinguish the real role of operator
"::" in an expression.
[Ambiguity Examples]
class A { public: static int i; };
class B: public A { public: static A A; };
What is the meaning of the expression "B::A::i"? If we consider
the first "::" as the scope resolutor, "B::A::i" means the
interger "i" defined in the base class. But if we consider the
first "::" as a selector, the expression denotes the integer
defined the member object A which is defined in class B.
Thoung in fact the integer "i" is unique in this case, but how
about the following example:
class A { public: static int i; };
class A_ { public: static int i; };
class B: public A { public: static A_ A; };
Now "B::A::i=100" will have different effect if we explain "::"
in different meaning. Further, if we consider expression:
B b;
b.A::i =100;
Which "i" should get the value "100"? It depends on whether "::"
is a selector or a scope resolute.
Example2
class A { public: class NA {}; };
class B: public A
{ public:
class A { public: class NA{}; };
};
What is the meaning of the expression "B::A::NA"?
We can set up a rule to avoid the ambiguity: whenever the ambiguity
happens, we apply the scope resolute meaning to the operator "::".
But how about if the user wants the selector meaning rather than the
scope resolute? For example, in expression "B::A::NA", I actually
mean the class NA nexted in class A nested in class B, not the NA
nested in global class A.
_____________________________________________________________________
_____________________________________________________________________
[Solution]
We use "::" only as a scope resolute. Whenever a selector must be used, use
operator ".". Then we come to a clear solution.
In example:
class A { public: static int i; };
class A_ { public: static int i; };
class B: public A { public: static A_ A; };
B b;
"B.A::i" denotes the integer in A, where "A::" is a scope resolute;
"B.A.i" denotes the integer of A_.
Note that a static member is also a member of the object, therefer,
"b.A::i" denotes the integer in A;
"b.A.i" denotes the integer in A_;
In example:
class A { public: class NA {}; };
class B: public A
{ public:
class A { public: class NA{}; };
};
"B.A::NA" denotes the NA nested in global class A (i.e. A.NA)
"B.A.NA" denotes the NA nested in nested class A in B;
Nested class cannot be accessed through objects.
_____________________________________________________________________
_____________________________________________________________________
[Syntatic Modification]
qualified-name
constrained-name
constrained-name . qualified-name
constrained-name
:: simple-name
simple-name :: constrained-name
simple-name
identifier
(qualified-name)
Note that simple-name can be a parenthesized qualified name. Thus we
can have the expression like:
C.NC.(BC1.NBC)::BBC1.NBBC
to denote a nested class NBBC in the following class definitions:
class BBC1
{ public:
class NBBC {};
};
class BBC2
{ public:
class NBBC {};
};
class BC1
{ public:
class NBC: public BBC1, public BBC2 {};
};
class BC2
{ public:
class NBC: public BBC1, public BBC2 {};
};
class C
{ public:
class NC: public BC1.NBC, public BC2.NBC {};
};
_____________________________________________________________________
Author: erc@netcom.com (Eric Smith)
Date: Sat, 31 Oct 1992 15:58:05 GMT Raw View
In article <1992Oct22.232803.14743@cadsun.corp.mot.com> shang@corp.mot.com writes:
> b.A::i // scope resolute, resolve in favor of base
> B::A::i // member selector, resolve in favor of member by BC++
> // scope resolute, resolve in favor of base by MS C/C++
> B::A::NA // member selector, resolve in favor of member
The operator precedence of :: is higher than that of . so b.A::i would
correctly mean the A::i member of object b.
Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Mon, 2 Nov 92 15:50:35 GMT Raw View
In article <1992Oct31.155805.6176@netcom.com> erc@netcom.com (Eric Smith)
writes:
> In article <1992Oct22.232803.14743@cadsun.corp.mot.com> shang@corp.mot.com
writes:
> > b.A::i // scope resolute, resolve in favor of base
> > B::A::i // member selector, resolve in favor of member by BC++
> > // scope resolute, resolve in favor of base by MS C/C++
> > B::A::NA // member selector, resolve in favor of member
>
>
> The operator precedence of :: is higher than that of . so b.A::i would
> correctly mean the A::i member of object b.
I didn't mention any problem of operator"::" with operator".".
No problem with their precedence order. The problem is the
ambiguious semantics of operator"::". Given an expression
"A::B", should "B" be a member (static member or nested class)
or a base class? When ambiguity happens, which has the
precedence? The member, or the base class? Unfortunately,
the rule is not clear. It is quite confused.
Daivd Shang