Topic: Should the compiler warn for pure virtual methods calls within constructor?


Author: "ShivKumar G." <g.shivkumar@tek.COM>
Date: 1998/05/26
Raw View
Hi,
    You can avoid the error by adding a dummy body to it. Here it goes.
   virtual void foo()=0
    {   }
I assume it should not give any errors now.
Regards
Shivkumar

Thomas R. Schar wrote in message <6kau40$63m$1@fang.dsto.defence.gov.au>...
Hi All,

I had a problem with some code that I wrote, and after I solved
the problem, I thought the compiler should have issued some sort of
warning.  However, I will agree it was a silly mistake.

class X{
public:
    X(){foo();}
    virtual void foo()=0;
};
class Y:public X{
public:
    virtual void foo(){cout<<"Y::foo()\n";}
};
int main(){
    Y y;
    y.foo();
}

yielded a runtime error with "pure virtual method invoked".
Should the compiler have warned about this?

Well, I guess my first question is,
    (a) are virtual methods within a constructor statically resolved, or
         are they still accessed via the vtableptr?
    (b) if via the vtableptr, then it's understandable.
    (c) if it is statically resolved, then why doesn't it warn you??
         it must know it is pure virtual?

Interestingly enough, gcc/g++ 2.8.0 came up with a compilation error.
VC++5.0 came up with a link error.
Both CC4.1, and Borland C++5.02 compiled and linked fine, but came up
with a runtime error.

So who is correct?  (or more correct?)

Thanks for any responses.
Thomas.



[ 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              ]
---
[ 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: Paul Black <paul.black@vf.vodafone.co.uk>
Date: 1998/05/26
Raw View
"ShivKumar G." <g.shivkumar@tek.COM> wrote back to front:
>
> Hi,
>     You can avoid the error by adding a dummy body to it. Here it goes.
>    virtual void foo()=0
>     {   }
> I assume it should not give any errors now.

It won't. It's not valid syntax. Secondly, because the call is a
virtual call, it will produce a run time error even though a body
is defined. To call X::foo() you would have to say X::foo() - but
then that's not a virtual call.

Paul
---
[ 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: "Phlip" <tegan@deltanet.com>
Date: 1998/05/26
Raw View
Paul Black wrote:

>"ShivKumar G." <g.shivkumar@tek.COM> wrote back to front:
>>
>> Hi,
>>     You can avoid the error by adding a dummy body to it. Here it goes.
>>    virtual void foo()=0
>>     {   }
>> I assume it should not give any errors now.
>
>It won't. It's not valid syntax. Secondly, because the call is a
>virtual call, it will produce a run time error even though a body
>is defined. To call X::foo() you would have to say X::foo() - but
>then that's not a virtual call.

It will - it is valid syntax. You are allowed to give a pure virtual a body,
and calling it accidently through a constructor will not produce a runtime
error.

The compiler cannot be expected to catch this kind of call at compile time
because the call might happen inside another member function or something.

  --  Phlip
======= http://users.deltanet.com/~tegan/home.html =======
Watch At Home on the Range! at:
    www.athomeontherange.com



[ 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: "Thomas R. Schar" <thomas.schar@dsto.defence.gov.au>
Date: 1998/05/27
Raw View
Hi All,

Phlip wrote in message <6kecl1$hij$1@news01.deltanet.com>...
>Paul Black wrote:
>>"ShivKumar G." <g.shivkumar@tek.COM> wrote back to front:
>>>
>>> Hi,
>>>     You can avoid the error by adding a dummy body to it. Here it goes.
>>>    virtual void foo()=0
>>>     {   }
>>> I assume it should not give any errors now.
>>It won't. It's not valid syntax. Secondly, because the call is a
>>virtual call, it will produce a run time error even though a body
>>is defined. To call X::foo() you would have to say X::foo() - but
>>then that's not a virtual call.
>It will - it is valid syntax. You are allowed to give a pure virtual a
body,
>and calling it accidentally through a constructor will not produce a
runtime
>error.
As far as I understand it, it is perfectly legal to provide a body to
a pure virtual function.  But as far as I understand, you are forced
to explicitly, as in "X::foo()", name the function to invoke the body.
But by explicitly supplying the class name, the function is resolved
statically, and any virtuality involved is disregarded (AFAIK).

Thus, even if you do supply a body for the pure virtual method, if
you refer to it as "foo()", not "X::foo()", it will cause the invocation
of a pure virtual method -- not normally a Good Thing(TM) :)


>The compiler cannot be expected to catch this kind of call at compile time
>because the call might happen inside another member function or something.
I agree that the compiler can certainly not be expected to catch this error
outside of the constructor, but within it?
AFAIK within a constructor, it is possible to statically resolve all virtual
calls to its own methods.
However, if all virtual functions are simply accessed via their vtableptr,
then
it makes a little more sense.

Thomas.
---
[ 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: "Phlip" <tegan@deltanet.com>
Date: 1998/05/27
Raw View
Thomas R. Schar wrote:

>As far as I understand it, it is perfectly legal to provide a body to
>a pure virtual function.

Yep. Read the /Effective C++/ books (by my tonsorial idol, Scott Meyers) to
learn why it sucks but makes sense to do so sometimes.

>But as far as I understand, you are forced
>to explicitly, as in "X::foo()", name the function to invoke the body.
>But by explicitly supplying the class name, the function is resolved
>statically, and any virtuality involved is disregarded (AFAIK).


Adding an explicit type always squelches any possibility of a virtual
dispatch, as does calling the function from outside a completely formed
object:

    X x;
    x.foo ();  //  not thru 'this' pointer

>Thus, even if you do supply a body for the pure virtual method, if
>you refer to it as "foo()", not "X::foo()", it will cause the invocation
>of a pure virtual method -- not normally a Good Thing(TM) :)

Nope. Pure means "I might not have a body - but whether I do or not you
can't make a complete object of me." Calling that body is another issue.

The third way to squelch dispatch is to construct. Students frequently hit
this when (possibly coming from a Java ... heritage) they try to virtually
initialize something based on what the fully formed object will be. Java
supports this because it pre-initializes the entire object. C++ does not
permit virtual calls out of a constructor of a sub-object because the outer
object does not really exist yet and its member values are all undefined.
(But there are other ways around this!)

>>The compiler cannot be expected to catch this kind of call at compile time
>>because the call might happen inside another member function or something.

>I agree that the compiler can certainly not be expected to catch this error
>outside of the constructor, but within it?
>AFAIK within a constructor, it is possible to statically resolve all
virtual
>calls to its own methods.
>However, if all virtual functions are simply accessed via their vtableptr,
>then
>it makes a little more sense.

But dispatch is squelched - the compiler bypasses the 'vtable', and
hard-codes a direct call to a purified address. It does this with full
awareness the result will (without a fall-back body) go boom, because the
Standard requires it not to complain.

The Standard can only require a diagnostic if the compiler could possibly
catch every single attempt to break the rule, no matter how convoluted. This
is why things like null-references are never flagged, even when flagrant.
The constructor might call a non-virtual function that calls a virtual
function, and the compiler has no obligation to read that function and flag
any virtual calls. A 'lint' might.

This question of virtual dispatch through a constructor is one of the
higher-level FAQs on the C++ newsgroups, and I usually answer it by pointing
out that Construction and Initialization are two different actions. C++
usually lets us lump them together, but programmers must keep them separate
in their minds. Construction does the minimum possible to let the destructor
not crash. Initialization should only happen to complete objects.

  --  Phlip
======= http://users.deltanet.com/~tegan/home.html =======
Watch At Home on the Range! at:
    www.athomeontherange.com
---
[ 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: jkanze@otelo.ibmmail.com
Date: 1998/05/27
Raw View
In article <6kg2eo$qqn$1@news01.deltanet.com>,
  "Phlip" <tegan@deltanet.com> wrote:
>
> Thomas R. Schar wrote:
>
> >As far as I understand it, it is perfectly legal to provide a body to
> >a pure virtual function.
>
> Yep. Read the /Effective C++/ books (by my tonsorial idol, Scott Meyers) to
> learn why it sucks but makes sense to do so sometimes.
>
> >But as far as I understand, you are forced
> >to explicitly, as in "X::foo()", name the function to invoke the body.
> >But by explicitly supplying the class name, the function is resolved
> >statically, and any virtuality involved is disregarded (AFAIK).
>
> Adding an explicit type always squelches any possibility of a virtual
> dispatch, as does calling the function from outside a completely formed
> object:
>
>     X x;
>     x.foo ();  //  not thru 'this' pointer

Adding an explicit type causes static resolution of the function name,
starting at the class given.  But calling the function on a completely
formed object has no effect, as such.  The function called still
depends on the dynamic type (and not the static type) of the expression;
in this particular case, the compiler is able to prove that the dynamic
type must be X, and so it knows which function to call.  (All compilers
that I am familiar with do this optimization, but it is certainly not
required by the standard.)

> >Thus, even if you do supply a body for the pure virtual method, if
> >you refer to it as "foo()", not "X::foo()", it will cause the invocation
> >of a pure virtual method -- not normally a Good Thing(TM) :)
>
> Nope. Pure means "I might not have a body - but whether I do or not you
> can't make a complete object of me." Calling that body is another issue.

See Steve Clamage's posting: pure means that the dynamic call mechanism
can never resolve to that function, even if it exists.  The fact that
you cannot instantiate if there are pure virtual functions derives from
this fact, and not the other way around.

> The third way to squelch dispatch is to construct.

There are no special rules concerning function resolution in constructors.
A constructor works exactly as any other function in this respect.
During the execution of a constructor, of course, the dynamic type
of the object is that of the constructor being executed.

> Students frequently hit
> this when (possibly coming from a Java ... heritage) they try to virtually
> initialize something based on what the fully formed object will be. Java
> supports this because it pre-initializes the entire object. C++ does not
> permit virtual calls out of a constructor of a sub-object because the outer
> object does not really exist yet and its member values are all undefined.
> (But there are other ways around this!)
>
> >>The compiler cannot be expected to catch this kind of call at compile
time
> >>because the call might happen inside another member function or
something.
>
> >I agree that the compiler can certainly not be expected to catch this
error
> >outside of the constructor, but within it?
> >AFAIK within a constructor, it is possible to statically resolve all
> virtual
> >calls to its own methods.
> >However, if all virtual functions are simply accessed via their vtableptr,
> >then
> >it makes a little more sense.
>
> But dispatch is squelched - the compiler bypasses the 'vtable', and
> hard-codes a direct call to a purified address.

Could you please site words in the FDIS to justify this.  I can find
nothing to this effect.

> It does this with full
> awareness the result will (without a fall-back body) go boom, because the
> Standard requires it not to complain.

The standard never forbids a warning.  A compiler can issue a warning
whenever it likes.

> The Standard can only require a diagnostic if the compiler could possibly
> catch every single attempt to break the rule, no matter how convoluted.
This
> is why things like null-references are never flagged, even when flagrant.

I suspect it is more a case that the error is so rare as to not be
worth checking (since the standard doesn't require it).  The same thing
could be said about returning a pointer to a local variable (which only
becomes undefined behavior when the caller accesses the pointer).  The
standard allows this, but most compilers will warn anyway.

> The constructor might call a non-virtual function that calls a virtual
> function, and the compiler has no obligation to read that function and flag
> any virtual calls. A 'lint' might.
>
> This question of virtual dispatch through a constructor is one of the
> higher-level FAQs on the C++ newsgroups, and I usually answer it by
pointing
> out that Construction and Initialization are two different actions.

The standard explicitly says they are the same.  It's an arbitrary
definition, in a way, but it is the usual way to talk about C++, and
anything else leads to confusion.

> C++
> usually lets us lump them together, but programmers must keep them separate
> in their minds. Construction does the minimum possible to let the
destructor
> not crash. Initialization should only happen to complete objects.

According to the standard, and object is only complete once all
initialization has taken place.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading


[ 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              ]