[comp.lang.c++] Why can't non-virtual functions override virtual ones?

petergo@microsoft.UUCP (Peter GOLDE) (11/09/90)

In the ARM, p. 209, it says:

"An overriding function is itself considered virtual.  The virtual
specificier may be used for an overriding function in the derived
class, but such use is redundant."

No justification for this restriction/feature is offered.

I'm curious as to why this was put in.  It seems to me that it
would be a very useful feature to be able to override a virtual
function with a non-virtual function; this would allow more
efficient access when the type of the object was known.  This
is especially important when inline functions are used.

To be specific, I would like to be able to do things like.

struct B {
    virtual int foo() = 0;
};

struct D: public B {
    int foo()  { return 2; }
};

struct D2: public B {
    int foo()  { return 3;}
};

main()
{
    B *pb = new D;
    D *pd = new D;
    D2 *pd = new D2;
    int x;

    x = b->foo();	    // should do virtual call
    x = d->foo();	    // should inline
    x = d2->foo();	    // also should inline
}

In essence, not putting "virtual" makes the claim that
this implemention of the function will never be overridden.
There doesn't seem any reason not to allow this claim
for for functions which are themselves overriding other functions;
this shouldn't make a difference.

Given that C++ has the feature of allowing non-virtual functions
for efficiency purposes, why are they restricted in this way?

--Peter Golde		  petergo%microsoft@uunet.uu.net

vaughan@mcc.com (Paul Vaughan) (11/11/90)

   From: petergo@microsoft.UUCP (Peter GOLDE)
   Newsgroups: comp.lang.c++
   Date: 9 Nov 90 01:04:41 GMT
   Reply-To: petergo@microsoft.UUCP (Peter GOLDE)
   Organization: Microsoft Corp., Redmond WA
   Lines: 50

   In the ARM, p. 209, it says:

   "An overriding function is itself considered virtual.  The virtual
   specificier may be used for an overriding function in the derived
   class, but such use is redundant."

   No justification for this restriction/feature is offered.

   I'm curious as to why this was put in.  It seems to me that it
   would be a very useful feature to be able to override a virtual
   function with a non-virtual function; this would allow more
   efficient access when the type of the object was known.  This
   is especially important when inline functions are used.

Both cfront and g++ already allow inlining or efficient access when
the exact type of an object is already known.

   To be specific, I would like to be able to do things like.

   struct B {
       virtual int foo() = 0;
   };

   struct D: public B {
       int foo()  { return 2; }
   };

   struct D2: public B {
       int foo()  { return 3;}
   };

   main()
   {
       B *pb = new D;
       D *pd = new D;
       D2 *pd = new D2;
       int x;

//Here the exact types of the objects pointed to by B, D, and D2 are
//no longer known.  Of course, a little more strenuous analysis might be
//able to determine the types, but I don't think cfront or g++ can do
//this.

       x = b->foo();	    // should do virtual call
       x = d->foo();	    // should inline
       x = d2->foo();	    // also should inline
   }

   In essence, not putting "virtual" makes the claim that
   this implemention of the function will never be overridden.
   There doesn't seem any reason not to allow this claim
   for for functions which are themselves overriding other functions;
   this shouldn't make a difference.

Note that declaring a non-virtual function does not currently make
"the claim that this implemention of the function will never be
overridden."  It simply means that the function actually invoked
depends on the pointer (or reference) type used to invoke it, as
opposed to always invoking the most specific version. Nonetheless,
there is perhaps some merit to this idea, but I think it would be
extremely confusing.  Consider this example.

struct DD: public D {
  virtual int foo() { return 4; }
};

main() {
  DD* pdd = new DD;
  B* pb = pdd;
  D* pd = pdd;
  int x;

  x = b->foo();	    // x = 4
  x = d->foo();	    // x = 2
  x = dd->foo();    // x = 4
}

It seems to me that it would be extremely easy to omit a "virtual"
somewhere and thereby get some pretty bizarre behavior.  I would
assume that that was the original reason for ATT's decision.  Either
that or they simply didn't think of this possible meaning or thought
of something different and rejected it.


 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan