[comp.lang.c++] cant use virtuals in base constructors

dove@rocket.stars.flab.Fujitsu.JUNET (Webster Dove) (05/04/89)

The following program prints
base
base
base
derived

and I wish it would print

base
base
derived
derived

This happens with cfront and g++ also.

// -*- C++ -*-

#include <stream.h>

class base
{
public: 
  virtual void foo() { cout << "base"; }
  base() { foo(); }
};

class derived : base
{
public:
  virtual void foo() { cout << "derived"; }
  derived() {};
};

main()
{
  base x;
  x.foo();

  derived y;	// Prints "base" should print "derived".
  y.foo();
}

Consider the case of someone implementing a base class for others to
use (e.g. an error handler).  I wanted to use this technique to tell
at construction time that a derived class had failed to implement its
own method for something (e.g. type_string()).  I would do this by
invoking the virtual in the base constructor, and having a dummy
method in the base class that I could detect.


class base
{
public: 
  virtual char *type_string() { return("(unknown)"); }
  base()
   {
     if(strcmp(type_string(), "(unknown)") == 0)
     {
       cerr << "Illegal derived class lacks a type_string() method\n";
       abort();
     }
   }
};

In c++ 1.x I cannot achieve this at compile time with something
equivalent to the (:required_methods 'type_string) construct in LISP
flavors.  I participated in the discussion about the lack of any
compile time warning of the failure (due to some minor spelling or
argument declaration error) of a derived method declaration to
rendezvous succesfully with a base class virtual.

The upshot was "make the base method a dummy that fails if it isn't
overloaded by the derived".  Well, I thought, since I can't detect
this at compile time, I will invoke the afore mentioned method in the
base constructor to check this early out rather than wait some
indeterminate time for the program to call the method.

I cannot achieve this at construction time since virtual methods don't
behave as virtual methods in the base constructor (this is the
intended behavior according to Michael Tiemann).

Can someone suggest a straighforward way to do this?  Will c++ 2.0
give me some capability to detect such coding failures gracefully?
(Whatever happened to :required-methods, :before, :after, ...?)

Web Dove

P.S.

Please reply to me via email as well, because I don't often get a
chance to check the news.
--
		Dr. Webster Dove
		Computing Systems and Architectures
		Advanced Signal Processing Engineering (ASPEN) Dept.
		Sanders Associates (a Lockheed Company)

jss@hector.UUCP (Jerry Schwarz) (05/05/89)

In article <DOVE.89May4223113@rocket.stars.flab.Fujitsu.JUNET> dove@rocket.stars.flab.Fujitsu.JUNET (Webster Dove) writes:
>

The reasons for calls to a virtual member function  in a base
constructor to be made to the base version of the virtual have been
discussed in this group several times recently.  In summary, its
because the members added in the derived class have not yet been
initialized.

>
>Consider the case of someone implementing a base class for others to
>use (e.g. an error handler).  I wanted to use this technique to tell
>at construction time that a derived class had failed to implement its
>own method for something (e.g. type_string()).  I would do this by
>invoking the virtual in the base constructor, and having a dummy
>method in the base class that I could detect.
>

In the pre-release of 2.0 there is a way to detect this at compile
time.

class B {
public: virtual void f() = 0 ; // f must be supplanted in all
			       // derived classes.  Allocation of
			       // a B (directly or via new) is not
			       // allowed.  
} ;

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (05/08/89)

In article <11492@ulysses.homer.nj.att.com> jss@hector.UUCP (Jerry Schwarz) writes:
>
>In the pre-release of 2.0 there is a way to detect this at compile
>time.
>
>class B {
>public: virtual void f() = 0 ; // f must be supplanted in all
>			       // derived classes.  Allocation of
>			       // a B (directly or via new) is not
>			       // allowed.  
>} ;

That's terrific!  I mean it!  We have been needing a feature like this!

One question.  You said that "f must be supplanted" in all derived classes.
Supplanted how?  Will this be legal?  (I hope so!)

	class base {
	public:
		virtual void f() = 0;
	};

	class middle : public base {
	public:
		virtual void f() = 0;	// force leaves to supplant f()
	};

	class derived : public middle {
	public:
		virtual void f() {}	// finally!
	};


-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

ark@alice.UUCP (Andrew Koenig) (05/09/89)

In article <198@riunite.ACA.MCC.COM>, rfg@riunite.ACA.MCC.COM (Ron Guilmette) writes:

-> One question.  You said that "f must be supplanted" in all derived classes.
-> Supplanted how?  Will this be legal?  (I hope so!)

-> 	class base {
-> 	public:
-> 		virtual void f() = 0;
-> 	};

-> 	class middle : public base {
-> 	public:
-> 		virtual void f() = 0;	// force leaves to supplant f()
-> 	};

-> 	class derived : public middle {
-> 	public:
-> 		virtual void f() {}	// finally!
-> 	};

Yes.

In this particular example, the semantics will not change
if you omit the definition of middle::f().

You can also omit `virtual' in middle::f and derived::f.
-- 
				--Andrew Koenig
				  ark@europa.att.com