Topic: Virtual inheritance and polymorphism in constructors


Author: James.Kanze@dresdner-bank.com
Date: 1999/06/07
Raw View
In article <3756AB13.1ED0@eae.com>,
  neppert.gernot@eae.com wrote:
>
> James Kuyper wrote:
> > Section 12.7 p3: "When a virtual function is called directly or
> > indirectly from a constructor (including from the _mem-initializer_
for
> > a data member) or from a destructor, and the object to which the
call
> > applies is the object under constructions or destruction, the
function
> > called is the one defined in the constructor's own class or in one
of
> > its bases, but not a function overriding it in a class derived from
the
> > constructor or destructor's class, or overriding it in one of the
other
> > base classes  of the most derived object (1.8)."
>
> > In short: you can call var->foo() from Base, but it will call
> > Base::foo(), not V2::foo(), nor Derived::foo(). When there's a
vtable
> > pointer, this can be implemented by having its contents possibly
change
> > at the start of each constructor. Note the "directly or indirectly"
-
> > you can't avoid this by using the 'var' pointer.
>
> The section you cite says:
> "AND THE OBJECT TO WHICH THE CALL APPLIES is the object under
> constructions or destruction"
> This is NOT the case here! It's not the "this"-pointer that's being
used
> here.

Who cares what pointer it is?  The pointer points to a specific object;
more correctly, the pointer points to the V1 part of the object.  The
dynamic type of that object is Base, because we are executing in the
constructor.  Who set the pointer is irrelevant to the argument.  You
don't really want different functions to be called for the same object,
depending on who set the pointer, do you?  That would really be
counter-intuitive.

> The V2-object which "var" points to is not under construction anymore.

The object var points to has two types: the static type, which is always
V1, and the dynamic type, which varies during construction, to finally
become Derived.  var only points to a V2-object during the construction
of the V2.

> It's just one complete object of type V2 that happens to be a part of
> the class Derived.

There is no "complete" object of type V2.  There will be a complete
object of type Derived, but we aren't there yet.  The rules for
constructors hold.

> Neither the pointer var going is going to be changed by the Base-ctor,
> nor the vtable of the V2-object.

The pointer var continues to point to the V1 part of the given object.
The pointer var is not changed.  The vptr of the V1 object which var
points to does change, on entering each constructor, and is required to
do so.

> (OK, I admit it: My defiant arguing is being supported only by the
> output of a single C++ compiler. Even if it turns out that you're
> right by the standard, let's give it a try on different platforms!)

The only compiler I have access to at present is an outdated g++.  But
generally, whenever I've looked at the generated code for a constructor,
it starts with the following pattern:

    call all base class constructors
    set up vptr for myself and my base classes.

In your case, you will typically have vtables with names like:
__vtbl_V1, __vtbl_V1_in_V2, __vtbl_V1_in_Base, and
__vtbl_V1_in_Derived.  (In the case of virtual inheritance, it is seldom
that the compiler will be able to merge the vtables.)  The constructor
for V1 will set the V1 vptr to __vtbl_V1, the construtor for V2 will set
it to __vtbl_V1_in_V2, the constructor for Base to __vtbl_V1_in_Base,
and the constructor for Derived to __vtbl_V1_in_Derived.  This is pretty
much the standard implementation.  Whether the constructor for Base is
called from the the constructor from Derived, or for a complete object,
changes nothing: once the base classes have been constructed, it sets
the vptr for V1 to __vtbl_V1_in_Base.  And this vtable had better not
contain any reference to functions in V2, because if the object being
constructed is just a Base, there is no V2.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient=E9e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gernot <neppert.gernot@eae.com>
Date: 1999/06/03
Raw View
James Kuyper wrote:
> Section 12.7 p3: "When a virtual function is called directly or
> indirectly from a constructor (including from the _mem-initializer_ for
> a data member) or from a destructor, and the object to which the call
> applies is the object under constructions or destruction, the function
> called is the one defined in the constructor's own class or in one of
> its bases, but not a function overriding it in a class derived from the
> constructor or destructor's class, or overriding it in one of the other
> base classes  of the most derived object (1.8)."
>


> In short: you can call var->foo() from Base, but it will call
> Base::foo(), not V2::foo(), nor Derived::foo(). When there's a vtable
> pointer, this can be implemented by having its contents possibly change
> at the start of each constructor. Note the "directly or indirectly" -
> you can't avoid this by using the 'var' pointer.
>


The section you cite says:
"AND THE OBJECT TO WHICH THE CALL APPLIES is the object under
constructions or destruction"
This is NOT the case here! It's not the "this"-pointer that's being used
here.
The V2-object which "var" points to is not under construction anymore.
It's just one complete object of type V2 that happens to be a part of
the class Derived.
Neither the pointer var going is going to be changed by the Base-ctor,
nor the vtable of the V2-object.

(OK, I admit it: My defiant arguing is being supported only by the
output of a single C++ compiler. Even if it turns out that you're
right by the standard, let's give it a try on different platforms!)


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/06/04
Raw View
In article <3756AB13.1ED0@eae.com>,
  neppert.gernot@eae.com wrote:
>
> James Kuyper wrote:
> > Section 12.7 p3: "When a virtual function is called directly or
> > indirectly from a constructor (including from the _mem-initializer_
for
> > a data member) or from a destructor, and the object to which the
call
> > applies is the object under constructions or destruction, the
function
> > called is the one defined in the constructor's own class or in one
of
> > its bases, but not a function overriding it in a class derived from
the
> > constructor or destructor's class, or overriding it in one of the
other
> > base classes  of the most derived object (1.8)."
>
> > In short: you can call var->foo() from Base, but it will call
> > Base::foo(), not V2::foo(), nor Derived::foo(). When there's a
vtable
> > pointer, this can be implemented by having its contents possibly
change
> > at the start of each constructor. Note the "directly or indirectly"
-
> > you can't avoid this by using the 'var' pointer.
>
> The section you cite says:
> "AND THE OBJECT TO WHICH THE CALL APPLIES is the object under
> constructions or destruction"
> This is NOT the case here! It's not the "this"-pointer that's being
used
> here.

Who cares what pointer it is?  The pointer points to a specific object;
more correctly, the pointer points to the V1 part of the object.  The
dynamic type of that object is Base, because we are executing in the
constructor.  Who set the pointer is irrelevant to the argument.  You
don't really want different functions to be called for the same object,
depending on who set the pointer, do you?  That would really be
counter-intuitive.

> The V2-object which "var" points to is not under construction anymore.

The object var points to has two types: the static type, which is always
V1, and the dynamic type, which varies during construction, to finally
become Derived.  var only points to a V2-object during the construction
of the V2.

> It's just one complete object of type V2 that happens to be a part of
> the class Derived.

There is no "complete" object of type V2.  There will be a complete
object of type Derived, but we aren't there yet.  The rules for
constructors hold.

> Neither the pointer var going is going to be changed by the Base-ctor,
> nor the vtable of the V2-object.

The pointer var continues to point to the V1 part of the given object.
The pointer var is not changed.  The vptr of the V1 object which var
points to does change, on entering each constructor, and is required to
do so.

> (OK, I admit it: My defiant arguing is being supported only by the
> output of a single C++ compiler. Even if it turns out that you're
> right by the standard, let's give it a try on different platforms!)

The only compiler I have access to at present is an outdated g++.  But
generally, whenever I've looked at the generated code for a constructor,
it starts with the following pattern:

    call all base class constructors
    set up vptr for myself and my base classes.

In your case, you will typically have vtables with names like:
__vtbl_V1, __vtbl_V1_in_V2, __vtbl_V1_in_Base, and
__vtbl_V1_in_Derived.  (In the case of virtual inheritance, it is seldom
that the compiler will be able to merge the vtables.)  The constructor
for V1 will set the V1 vptr to __vtbl_V1, the construtor for V2 will set
it to __vtbl_V1_in_V2, the constructor for Base to __vtbl_V1_in_Base,
and the constructor for Derived to __vtbl_V1_in_Derived.  This is pretty
much the standard implementation.  Whether the constructor for Base is
called from the the constructor from Derived, or for a complete object,
changes nothing: once the base classes have been constructed, it sets
the vptr for V1 to __vtbl_V1_in_Base.  And this vtable had better not
contain any reference to functions in V2, because if the object being
constructed is just a Base, there is no V2.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gernot <neppert.gernot@eae.com>
Date: 1999/06/01
Raw View
James.Kanze@dresdner-bank.com wrote:
> Basically, the question was: in the constructor for Base, what virtual
> functions should be called, those in V1, or those in V2.
>
> The rule is simple: within the constructor, the dynamic type of the
> object is that of the type of the constructor.  Within the constructor
> of Base, the dynamic type of the object is Base.  Base doesn't contain a
> V2, so there is *no* way any functions in V2 can possibly be called.
>

But this doesn't hold for the member "var" that is also used in the
Base-ctor. If the pointer "var" was correctly initialized (upon which
the example sploppily relies), then calling var->foo() within the
Base-ctor would surely invoke the overloaded function of any derived
object!
So the question arises: If the call "var->foo()" doesn't produce a core
dump, var must have been initialized. Since this can only have happened
in the V2-ctor, why is V2::foo not called?


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-deja.com
Date: 1999/06/01
Raw View
In article <3753EDAA.73BA@eae.com>,
  neppert.gernot@eae.com wrote:
> But this doesn't hold for the member "var" that is also used in the
> Base-ctor. If the pointer "var" was correctly initialized (upon which
> the example sploppily relies), then calling var->foo() within the
> Base-ctor would surely invoke the overloaded function of any derived
> object!
> So the question arises: If the call "var->foo()" doesn't produce a core
> dump, var must have been initialized. Since this can only have happened
> in the V2-ctor, why is V2::foo not called?

It seems I was not clear enough in my previous post, so let me try it
again. "var" was assigned value of "this" when V2 ctor was called. It
actually doesn't matter in ctor of which class "var" was assigned that
value, because in any case it would have been a value of &d. So the
question is what is the dynamic type of "var". The answer is simple: the
same as "this" at the same scope, because it points to the same object.
Since we are calling var->foo() from Base-ctor, virtual method table
pointer was adjusted to point to Base vmt; as a result Base::foo() was
called, which is the same as V1::foo().
Gene.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/06/02
Raw View
In article <3753EDAA.73BA@eae.com>,
  neppert.gernot@eae.com wrote:
>
> James.Kanze@dresdner-bank.com wrote:
> > Basically, the question was: in the constructor for Base, what
virtual
> > functions should be called, those in V1, or those in V2.
> >
> > The rule is simple: within the constructor, the dynamic type of the
> > object is that of the type of the constructor.  Within the
constructor
> > of Base, the dynamic type of the object is Base.  Base doesn't
contain a
> > V2, so there is *no* way any functions in V2 can possibly be called.
> >
>
> But this doesn't hold for the member "var" that is also used in the
> Base-ctor. If the pointer "var" was correctly initialized (upon which
> the example sploppily relies), then calling var->foo() within the
> Base-ctor would surely invoke the overloaded function of any derived
> object!
> So the question arises: If the call "var->foo()" doesn't produce a
core
> dump, var must have been initialized. Since this can only have
happened
> in the V2-ctor, why is V2::foo not called?

Once again, the hierarchy:

        V1
       /  \
      V2   Base
       \  /
      Derived

The type of the variable var is V1*.  The function V1::foo is virtual,
and redefined in V2.

Regardless of where or when var was initialized: var points to an object
with a V1 base class.  The function V1::foo is virtual.  The actual
function to be called *must* be that of the dynamic type (!= most
derived type) of the object.  In the constructor of Base, the dynamic
type is Base.  Base contains no V2, so no function in V2 may be called.
The fact that var was in fact initialized in the constructor of V2 is
irrelevant.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/06/02
Raw View
James.Kanze@dresdner-bank.com wrote:

[Explanation why V1::foo() gets called]

> At least no in the example code, where all of the pointers involved were
> either this or V1*.  An interesting question (IMHO) however, is what
> happens (or should happen) in the following case:
>

[Diamond, where one intermediate virtual class (L) stores this
into a pointer to L, and the other (R) calls through this pointer]

>
> In the line with the ??, we call the virtual function for an object
> whose static type is L.  A priori, the dynamic type is R, and so the
> function in VB should be called.  Except: L and R are not related.  I
> find it somewhat strange to think that an L* can point to an object
> whose dynamic type is R (and not D).

I've tested your code with egcs 1.0.3, and it indeed prints
"In VB" twice. However, interestingly, if I add a virtual
function L::bar(), this one can be called from within R::R().
However, even calling foo from within L::bar called from R::R()
generates "In VB", not "In L". f I override "foo" from within R
(and in D, too), the program prints "In R" for all calls.
Even more interestingly, dynamic_cast<L*>((VB*)this)
gives NULL _inside L::bar()_ (while dynamic_cast<L*>(this)
still returns the address, probably due to the compiler
using the fact that the static type is not changed at all
for optimizing away the runtime check).

Of course, this doesn't say what the standard mandates in this
case (I strongly doubt that calling VB::foo(), but L::bar()
is sanctioniced by the standard).
However, IMHO all this shows that the "dynamic type is static
type of running constructor" is not working too well, if virtual
inheritance is involved. It works well for non-virtual base
classes only because they are not shared, and therefore before
entering the constructor of the derived type, the dynamic type
and static type of each of their base objects are the same.

I'm not sure what the best wording would be; however, IMHO
an already constructed object should not be "downgraded"
again (except on destruction).
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gernot <neppert.gernot@eae.com>
Date: 1999/06/02
Raw View
gbush@my-deja.com wrote:
> question is what is the dynamic type of "var". The answer is simple: the
> same as "this" at the same scope, because it points to the same object.

Does it? I think it points to the V2-subobject that has already been
constructed before the Base-ctor is called.

> Since we are calling var->foo() from Base-ctor, virtual method table
> pointer was adjusted to point to Base vmt;

This is not the correct line of reasoning. You *can* call the most
derived virtual function for *any* object derived from class V1 within
the Base-ctor, except for the "this" - object, which is always of
dynamic type Base.

Given the order of invocation for all the ctors, it seems to me that
when Base-ctor is called, there is already a subobject of type V2, and
"var" points to it! So the output could well be "V2::foo()"
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/06/03
Raw View
[Re: the following hierarchy

        V1
       /  \
     V2    Base
       \  /
      Derived

with foo() a virtual member of V1, with a separate definition in each
class, and 'var' a V1* member of V1 that is left unitialized by V1's
ctor, but which is initialized by V2's ctor with 'this'. var->foo() is
called by Base's ctor.]

Gernot wrote:
>
> gbush@my-deja.com wrote:
....
> > Since we are calling var->foo() from Base-ctor, virtual method table
> > pointer was adjusted to point to Base vmt;
>
> This is not the correct line of reasoning. You *can* call the most
> derived virtual function for *any* object derived from class V1 within
> the Base-ctor, except for the "this" - object, which is always of
> dynamic type Base.

Section 12.7 p3: "When a virtual function is called directly or
indirectly from a constructor (including from the _mem-initializer_ for
a data member) or from a destructor, and the object to which the call
applies is the object under constructions or destruction, the function
called is the one defined in the constructor's own class or in one of
its bases, but not a function overriding it in a class derived from the
constructor or destructor's class, or overriding it in one of the other
base classes  of the most derived object (1.8)."

In short: you can call var->foo() from Base, but it will call
Base::foo(), not V2::foo(), nor Derived::foo(). When there's a vtable
pointer, this can be implemented by having its contents possibly change
at the start of each constructor. Note the "directly or indirectly" -
you can't avoid this by using the 'var' pointer.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/29
Raw View
What should be the output of the following code?

##include <iostream>

struct V1;

void callfoo(V1*);

struct V1
{
  V1* var;
  virtual void foo()
  {
    cout << "V1::foo()" << endl;
  }
};

struct V2:
  virtual V1
{
  V2()
  {
    var=this;
  }
  virtual void foo()
  {
    cout << "V2::foo()" << endl;
  }
};


struct Base:
  virtual V1
{
  Base()
  {
    foo();
    callfoo(this);
    var->foo();
    callfoo(var);
  }
};

struct Derived:
  virtual V2,
  Base
{
};

void callfoo(V1* v)
{
  v->foo();
}

int main()
{
  Derived d;
  V1* p=&d;
  p->foo();
}

egcs 1.0.3 gives:
V1::foo()
V1::foo()
V1::foo()
V1::foo()
V2::foo()

However, I think it should be V2::foo() each time:

According to CD2, 12.6.2 [class.base.init]/5, first all virtal bases
are processed. That is, first V1::V1() (implicit through both V2
and Base) is executed, then V2::V2() is executed. At this point, the
dynamic type of the object should IMHO be V2. Now Base::Base() is
executed. This constructor calls V1::V1(foo). But since V2::V2()
has already executed, I think the dynamic type of the V1 subobject
should already be V2, and therefore V2::foo() should be called.
Even more obvious it is for the var member: This is initialized in
V2::V2(), so its dynamic type should be V2. However, it gets
"downgraded" to a V1, when used in Base::Base().

So my question is: Who's right, egcs 1.0.3 or me?
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "G.B." <gbush@dejanews.com>
Date: 1999/05/29
Raw View

Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote in message
news:374BDBBD.4EB1BB4E@physik.tu-muenchen.de...
[snip...]
> egcs 1.0.3 gives:
> V1::foo()
> V1::foo()
> V1::foo()
> V1::foo()
> V2::foo()
>
[snip...]
>
> So my question is: Who's right, egcs 1.0.3 or me?

Answer: egcs :)

There is no question about the last line, it's clear should be V2::foo().
The first 4 lines, all proceede from Base, which knows nothing about
Derived, so you can figure out what's going on just looking at Base and V1.
struct Base:
  virtual V1
{
  Base()
  {
    foo();                // the only candidate is V1,
                             // compiler in fact discards virtual and calls
V1::foo()
    callfoo(this);    // calls (Base*)this->foo(), same effect
    var->foo();       // you can't cheat compiler, duhh!
                             // "var" points to the same object as "this"
(i.e. &d),
                             // and since we now in Base, vmt pointer is
pointing to Base_vmt,
                             // so annoing V1::foo() is called again
                             // to achieve the result you want, you
should've copied the vmt pointer,
                             // not just "this"
    callfoo(var);    // no different from previous
  }
};

Gene.

P.S. I could have missed something, it's too boring to read the standard
during a weekend :)




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/05/31
Raw View
In article <374BDBBD.4EB1BB4E@physik.tu-muenchen.de>,
  Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> What should be the output of the following code?

    [Code for the following hierarchy snipped...]

        V1
       /  \
     V2    Base
       \  /
      Derived

Basically, the question was: in the constructor for Base, what virtual
functions should be called, those in V1, or those in V2.

The rule is simple: within the constructor, the dynamic type of the
object is that of the type of the constructor.  Within the constructor
of Base, the dynamic type of the object is Base.  Base doesn't contain a
V2, so there is *no* way any functions in V2 can possibly be called.

At least no in the example code, where all of the pointers involved were
either this or V1*.  An interesting question (IMHO) however, is what
happens (or should happen) in the following case:

    L*          lp ;            //  Global variable for exposition
    VB*         vbp ;

    struct VB
    {
        virtual void    foo()
        {
            cout << "In VB\n" ;
        }
    } ;

    struct L : virtual VB
    {
        L()
        {
            lp = this ;
            vbp = this ;
        }

        virtual void    foo()
        {
            cout << "In L\n" ;
        }
    } ;

    struct R : virtual VB
    {
        R()
        {
            vbp->foo() ;        //  Should print "In VB"...
            lp->foo() ;         //  ??
        }
    } ;

    struct D : L , R
    {
    } ;

    int
    main()
    {
        D           aD ;
    }

In the line with the ??, we call the virtual function for an object
whose static type is L.  A priori, the dynamic type is R, and so the
function in VB should be called.  Except: L and R are not related.  I
find it somewhat strange to think that an L* can point to an object
whose dynamic type is R (and not D).

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]