Topic: (virtual) inheritance, ambiguities and :: operator


Author: James.Kanze@dresdner-bank.com
Date: 2000/12/06
Raw View
In article <3A2CF56E.8D0@free.fr>,
  Valentin Bonnard <Valentin.Bonnard@free.fr> wrote:
> James.Kanze@dresdner-bank.com wrote:

> > Well, I find that the :: operator is already a bit overloaded,
> > since on one hand, it can be used to navigate a hierarchy, and on
> > the other, it specifies a class or namespace from where to start
> > looking.

> At least these uses are related: they are about name lookup.

> There is a third, unrelated use: to disable virtualness.

This is actually just a side effect of the first use I specify.  It
doesn't actually disable virualness; it just restricts name lookup.
Of course, restricting *dyanmic* name lookup pretty much means that
the compiler will know that actual type found, and so won't use the
virtual mechanism.:-)

There's more to it than that, of course, since the name lookup with
T:: will find pure virtual functions that normal dynamic name lookup
will not find.  So Valentin's point is actually pretty correct: when
:: is used, name lookup becomes static, not dynamic.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 2000/12/06
Raw View
James.Kanze@dresdner-bank.com writes:

| In article <3A2CF56E.8D0@free.fr>,
|   Valentin Bonnard <Valentin.Bonnard@free.fr> wrote:
| > James.Kanze@dresdner-bank.com wrote:
|
| > > Well, I find that the :: operator is already a bit overloaded,
| > > since on one hand, it can be used to navigate a hierarchy, and on
| > > the other, it specifies a class or namespace from where to start
| > > looking.
|
| > At least these uses are related: they are about name lookup.
|
| > There is a third, unrelated use: to disable virtualness.
|
| This is actually just a side effect of the first use I specify.  It
| doesn't actually disable virualness; it just restricts name lookup.
| Of course, restricting *dyanmic* name lookup pretty much means that
| the compiler will know that actual type found, and so won't use the
| virtual mechanism.:-)

C++ has nothing named "*dynamic* name lookup".

Name lookup takes place at translation-time.  It is a pure static
notion.  However, the Standard speaks of "dynamic binding" which I
think is what we probably meant. The whole "name lookup" issue is
already complexe and there is no need to complexify it ;-)

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: James.Kanze@dresdner-bank.com
Date: 2000/12/04
Raw View
In article
<Pine.LNX.4.21.0012040042030.831-100000@deimos.solarsystem.gnu>,
  Gianni Luciani <gianni.luciani@tiscalinet.it> wrote:

> In article <900lrs$ubb$1@nnrp1.deja.com>,
> James.Kanze@dresdner-bank.com wrote

> >In article
> ><Pine.LNX.4.21.0011252013100.803-100000@deimos.solarsystem.gnu>,
> >  Gianni Luciani <gianni.luciani@tiscalinet.it> wrote:

> >> I have some questions for You:
>  ...
> >> class Start { ... };
> >> class Base : public Start { ... };
> >> class Derived1 : virtual public Base { ... };
> >> class Derived2 : virtual public Base { ... };
> >> class MI : public Derived1, public Derived2 { ... };
> >> class Final : public MI, public Start { ... };
> >> and trying to compile it with Borland C++Builder 5.0 Service Pack
> >> 1, I obtain the following warning :

> >> [C++ Warning] ProvaDerivazioneVirtual.h(52):
> >>  W8024 Base class 'Start' is also a base class of 'MI'

> >> while trying to compile it with VC++ 6.0 Service Pack 'I don't
> >> remember, but almost surely one of the last currently available'
> >> I obtain the following Error code :

> >> c:\pal\provastampa\provaderivazionevirtual.h(56) :
> >> error C2584: 'Final' : direct base 'Start' is inaccessible;
> >> already a base of 'MI'

> >> What's the correct behaviour ? The Inprise's compiler one, or the
> >> M$'s compiler one ?

> >I think that the code is wrong.  Since both compilers issue a
> >diagnostic, both are correct.

> >> Then I would like to throw another question:
> >>    why isn't possible to use the resolution operator ( :: ) to
> >>    disambiguate the above situation.

> >Because Start:: is ambiguous.  There are two instances of Start in
> >the object.  MI::Start:: is not ambiguous, but there is no way,
> >with the immediate hierarchy, of specifying the other Start.

> >The obvious solution is to introduce an intermediate class:

> >  class RenamedStart : public Start {} ;

> >  class Final : public MI, public RenamedStart {} ;

> >This should eliminate the diagnostics, since there is only one Start
> >whose constructor should be called by Final directly (the virtually
> >inherited one), and you can disambiguate any other use by means of
> >MI::Start or RenamedStart::Start.

> Yes, but ...  Hmmmm, OK I was not clear, but (how You can easily see
> giving a look at the folling part), I was asking if it's could be a
> good idea to extend resolution operator to let it disambiguate even
> the above ambiguous situation.  See after.

> >> for example stating that if pun is a Final * then
> >> pun->::Start::m_member1 will refer to Start member of Final
> >> directly accessible from the 'surface' of the object, while for
> >> example pun->::MI::Start ... will refer the member of the virtual
> >> inherited block ?  Also pun->::m_member will address a class own
> >> member while pun->m_member will address the possibly inherited
> >> one ?  Could the above approach be feasible in terms of
> >> efficiency, language implementation complexity etc ... ?  If this
> >> is the case why wasn't it be taken into account ?  On the
> >> contrary what are the main reasons for not allowing the above
> >> syntax ??
> >Yes

> >Why bother?  The solution, as described doesn't work, since the ::
> >in this case says to start looking at file scope, and not within
> >the hierarchy.  The problem is exceedingly rare in real code, and
> >there is a simple work-around.

> Yes, but I was proposing (clearly in a very 'tangled ?' way) an
> extension to resolution operator (:: ) to make it more flexible and
> to let it disambiguate much more situations.  than it's able by now.
> My proposal is to keep current meaning and add just a little bit of
> power when resolution operator is used after operator -> for a
> pointer or after operator .  for references.  The added meaning is
> that after operator ->, for example, :: can precisate 'the path'
> needed to reach a subobject with :: immediately after -> meaning
> 'surface' i.e. in the object itself and not into nested subobjects;
> so, for example, in the above situation, pun->::Start::m_memmber
> will refer to the Start object directly accessible 'from the
> surface' i.e. not nested in some other subobjects, while
> pun->MI::Start::m_member, or, equivalently,
> pun->::MI::Start::m_memmber will refer to the MI' subobject of type
> Start.  This extension could help disambiguating some situation.

Well, I find that the :: operator is already a bit overloaded, since
on one hand, it can be used to navigate a hierarchy, and on the other,
it specifies a class or namespace from where to start looking.
Technically, the first is only a special case of the second, but
psychologically, one tends to think of them differently.  At any rate,
I'm in no hurry to see any additional uses.

> I agree with You that 'The problem is exceedingly rare in real code,
> and there is a simple work-around.', but this extension could make
> operator :: much more flexible, and uniform with, for example, the
> way You use operator -> and operator (.) .  That's to say (I'm not
> able to better express the concept than this) as You can do the
> following object1->getString().c_str() the extension above let's You
> 'navigate' into nested subobjects, having a way to say the 'surface'
> of the object and to indicate the exact, precise nesting of the
> subobject You want to reach.  To give just another example, in my
> idea given the following definitions

The -> and . operators are not comparable, since they both use the
exact type on the left.  The :: operator simply says where to start
searching.

One could have imagined defining the :: operator to require an exact
match too.  It wasn't done, however, and doing so would break too much
existing code.

> class A { public: int pippo; // other defs/decls
> };
> class B : public A{ public: double paperino;// other defs/decls
> };

> B obj;
> B* objptr = &obj;

> the following statement objptr->::pippo; should issue a diagnostic
> warning that pippo isn't a 'own' member of B even if it's an
> inherited one.

Could you show even one use where this would be useful?

> Given that my questions about the feasibility in terms of
> efficiency, language implementation complexity etc, are (now)
> clearly about the costs of the above extension.  My next question
> was then why the above extension wasn't still taken into account ?
> And then what could be the main reasons/drawbacks for not allowing
> the above syntax extension (apart from rare usefulness You already
> pointed out) ??

In general, consider the following:

    struct Base { virtual int f() ; } ;
    struct Intermediate : Base {
    } ;
    struct Derived : Intermediate {
        virtual int f() ;
    } ;

    int
    Derived::f() {
        //  ...
        return Intermediate::f() ;
    }

You don't want Derived to know where Intermediate got its f() from.
Derived wants the f() which Intermediate provides.  Whether
Intermediate inherited it, or implements it directly, is an
implementation detail of Intermediate.

For this to work naturally, you need for :: to specify a scope from
which to start looking, and not an absolute class.  What you are
suggesting would either break this (:: specifies an absolute class),
or break orthogonality (:: sometimes specifies a scope from which to
start, but when used to raise ambiguity, specifies an absolute
class).  Given the infrequence of the problem, and the existance of a
work-around, I'd rather keep the orthogonality.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Valentin Bonnard <Valentin.Bonnard@free.fr>
Date: 2000/12/05
Raw View
James.Kanze@dresdner-bank.com wrote:

> Well, I find that the :: operator is already a bit overloaded, since
> on one hand, it can be used to navigate a hierarchy, and on the other,
> it specifies a class or namespace from where to start looking.

At least these uses are related: they are about name lookup.

There is a third, unrelated use: to disable virtualness.

Often, you need to disable virtualness and to navigate a
hierarchy at the same time (inherited::foo ()), and this
use is never combined with the specification of a class
or namespace because these functions are never virtual.

So the C++ language groups these two uses (navigating a
hierarchy and disabling virtualness), but they are
logically independent, and semantically unrelated.

--

Valentin Bonnard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Gianni Luciani <gianni.luciani@tiscalinet.it>
Date: 2000/12/03
Raw View
Subject: (virtual) inheritance and ambiguities and extensions to the :: operator

In article <900lrs$ubb$1@nnrp1.deja.com>,
James.Kanze@dresdner-bank.com wrote

>In article
><Pine.LNX.4.21.0011252013100.803-100000@deimos.solarsystem.gnu>,
>  Gianni Luciani <gianni.luciani@tiscalinet.it> wrote:
>
>> I have some questions for You:
>
>It would be a lot easier if you'd post each question in a separate
>article, with a relevant subject line.

Ooops, I beg Your (here Your meaning all other newsgroup readers, too) pardon !
I will avoid to make this mistake again.
By the way this is a reply of the former 'comp.std.c++' post.
See following main part ...

 ...
>> class Start { ... };
>> class Base : public Start { ... };
>> class Derived1 : virtual public Base { ... };
>> class Derived2 : virtual public Base { ... };
>> class MI : public Derived1, public Derived2 { ... };
>> class Final : public MI, public Start { ... };
>> and trying to compile it with Borland C++Builder 5.0 Service Pack 1,
>> I obtain the following warning :
>>
>> [C++ Warning] ProvaDerivazioneVirtual.h(52):
>>  W8024 Base class 'Start' is also a base class of 'MI'
>>
>> while trying to compile it with VC++ 6.0 Service Pack 'I don't
>> remember, but almost surely one of the last currently available' I
>> obtain the following Error code :
>>
>> c:\pal\provastampa\provaderivazionevirtual.h(56) :
>> error C2584: 'Final' : direct base 'Start' is inaccessible;
>> already a base of 'MI'
>>
>> What's the correct behaviour ? The Inprise's compiler one, or the
>> M$'s compiler one ?
>
>I think that the code is wrong.  Since both compilers issue a
>diagnostic, both are correct.
>
>> Then I would like to throw another question:
>>    why isn't possible to use the resolution operator ( :: ) to
>>    disambiguate the above situation.
>
>Because Start:: is ambiguous.  There are two instances of Start in the
>object.  MI::Start:: is not ambiguous, but there is no way, with the
>immediate hierarchy, of specifying the other Start.
>
>The obvious solution is to introduce an intermediate class:
>
>  class RenamedStart : public Start {} ;
>
>  class Final : public MI, public RenamedStart {} ;
>
>This should eliminate the diagnostics, since there is only one Start
>whose constructor should be called by Final directly (the virtually
>inherited one), and you can disambiguate any other use by means of
>MI::Start or RenamedStart::Start.
>

Yes, but ...
Hmmmm, OK I was not clear, but (how You can easily see giving a look at the folling part),
I was asking if it's could be a good idea to extend resolution operator to let
it disambiguate even the above ambiguous situation.
See after.

>> for example stating that if pun is a Final * then
>> pun->::Start::m_member1 will refer to Start member of Final directly
>> accessible from the 'surface' of the object, while for example
>> pun->::MI::Start ... will refer the member of the virtual inherited
>> block ?  Also pun->::m_member will address a class own member while
>> pun->m_member will address the possibly inherited one ?  Could the
>> above approach be feasible in terms of efficiency, language
>> implementation complexity etc ... ?  If this is the case why wasn't
>> it be taken into account ?  On the contrary what are the main
>> reasons for not allowing the above syntax ??
>Yes
>Why bother?  The solution, as described doesn't work, since the :: in
>this case says to start looking at file scope, and not within the
>hierarchy.  The problem is exceedingly rare in real code, and there is
>a simple work-around.

Yes, but I was proposing (clearly in a very 'tangled ?' way) an extension to
resolution operator
(:: ) to make it more flexible and to let it disambiguate much more situations.
than it's able by now.
My proposal is to keep current meaning and add just a little bit of power when
resolution operator is used after operator -> for a pointer or after operator .
for references.
The added meaning is that after operator ->, for example, :: can precisate 'the path'
needed to reach a subobject with :: immediately after -> meaning 'surface' i.e. in the
object itself and not into nested subobjects; so, for example, in the above situation,
pun->::Start::m_memmber will refer to the Start object directly accessible 'from
the surface' i.e. not nested in some other subobjects, while
pun->MI::Start::m_member, or, equivalently, pun->::MI::Start::m_memmber will
refer to the MI' subobject of type Start.
This extension could help disambiguating some situation.

I agree with You that 'The problem is exceedingly rare in real code, and there is
a simple work-around.', but this extension could make operator :: much more flexible,
and uniform with, for example, the way You use operator -> and operator (.) .
That's to say (I'm not able to better express the concept than this) as You can do the
following object1->getString().c_str() the extension above let's You 'navigate' into
nested subobjects, having a way to say the 'surface' of the object and to indicate the
exact, precise nesting of the subobject You want to reach.
To give just another example, in my idea given the following definitions

class A { public: int pippo; // other defs/decls
};
class B : public A{ public: double paperino;// other defs/decls
};

B obj;
B* objptr = &obj;

the following statement objptr->::pippo; should issue a diagnostic warning that pippo isn't
a 'own' member of B even if it's an inherited one.

Given that my questions about the
feasibility in terms of efficiency, language
implementation complexity etc, are (now) clearly about the costs of the above
extension.
My next question was then why the above extension wasn't
still taken into account ?
And then what could be the main
reasons/drawbacks for not allowing the above syntax extension (apart from rare usefulness
You already pointed out) ??

Gianni Luciani

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]