Article View: comp.std.c++
Article #2306Re: Why allow virtual function calls in constr
From: Steve Clamage
Date: Thu, 26 Oct 1995 00:15
Date: Thu, 26 Oct 1995 00:15
99 lines
4775 bytes
4775 bytes
In article j45@manuel.anu.edu.au, keagchon@mehta.anu.edu.au (Geoff Keating 9205156) writes:
>
>The draft WP says that [section class.cdtor:3]
>
> When a virtual function is called directly or indirectly from a con-
> structor (including from its ctor-initializer) or from a destructor,
> and the object to which the call applies is the object under construc-
> tion or destruction, the function called is the one defined in the
> constructor or destructor'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 complete object (_intro.object_).
>
>Why allow this, rather than refusing calls to virtual functions at
>all? It would be nice to say that `if I override this function, then
>the old version will _never_ be called on objects of this type'.
This language design decision is explained in the ARM, among other places.
Given
class base { ... };
class derived : public base { ... };
suppose we constuct an object of type derived.
The first thing that happens is that the base constructor runs. While that
constructor is running, the object has type base, not type derived. Hence,
any virtual functions that are called will never be those declared in
derived, because the object at this moment is not a derived object; it is
a base object. That is (part of) the C++ object model.
In other words, when a constructor runs, the object has exactly the type
of the constructor's class.
The same is true of destructors. When the body of the derived destructor
completes, the destructor for base runs. At that point, the object has
ceased being a derived (the derived part has been destroyed), and is now
a base object.
Other language designs are possible. For example, we could say that when
you construct a derived, the object is a derived even before the derived
constructor begins to run, and you get the derived virtual functions when
called from the base constructor or destructor. Sometimes that will be the
effect you want. But in the general case, member functions of derived
could be called which depend on the derived constructor having already
run, and on the derived destructor not yet having run. This will not always
be the case. We would need additional rules, such as
1. You cannot call a virtual function from a ctor/dtor, or
2. You have to write a virtual function so that it doesn't matter whether
the ctor or dtor for its type has run or not, or
3. If you call a virtual function from a ctor/dtor, the results are undefined.
With this object model, you cannot define the semantics of a virtual
function call from a ctor/dtor unless you somehow enforce option 2 above.
Example:
class base {
public:
virtual int f() { return 0; }
...
};
class derived : public base {
public:
virtual int f();
derived(const char* name) { str = new ifstream(name); }
~derived() { delete str; }
private:
ifstream* str;
};
int derived::f() {
int i;
*str >> i; // fails before ctor runs and after dtor runs
return i;
}
If a constructor or destructor for base calls f() and gets derived::f(),
you cannot define any semantics for the result. Hence my three options above.
This seems to me to be inferior to the actual C++ semantics.
Another alternative, used in some languages, is that the base ctors
and dtors are not run automatically. The derived class ctor/dtor specifies
the complete order of execution. This gives you the control you need to
let the above example work, but it also means, it seems to me, that the
derived class must know all about all its base classes. You lose the
modularity of needing to know only the interface of the base class. Any
change in any base class might require that you rewrite ctors and dtors
of derived classes. Some people think this model still provides an overall
advantage. I don't agree, but in any case, it isn't C++.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID:
<46mgqo$e5b@engnews2.Eng.Sun.COM>Path:
arc1-ca.pugleaf.net!128.32.155.1!mattReferences:
<46kuqc$j45@manuel.anu.edu.au>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!128.32.155.1!matt From: clamage@Eng.Sun.COM (Steve Clamage) Newsgroups: comp.std.c++ Subject: Re: Why allow virtual function calls in constr Date: 26 Oct 1995 00:15:44 GMT Organization: Sun Microsystems Inc. Approved: matt@physics10.Berkeley.EDU (Matt Austern) Message-ID: <46mgqo$e5b@engnews2.Eng.Sun.COM> References: <46kuqc$j45@manuel.anu.edu.au> Reply-To: clamage@Eng.Sun.COM NNTP-Posting-Host: physics10.berkeley.edu