Topic: Not initialising virtual bases in abstract classes.


Author: Maurice Bos <m-ou.se@m-ou.se>
Date: Thu, 18 Jul 2013 14:38:53 -0700 (PDT)
Raw View
------=_Part_61_32559328.1374183533555
Content-Type: text/plain; charset=ISO-8859-1

Hello,

Currently, the following code is invalid:

    struct base {
        explicit base(some_complicated_type);
        virtual void foo() = 0; // base is abstract
        virtual ~base();
    };

    struct left : virtual base {};
    struct right : virtual base {};

    struct derived : left, right {
        derived() : base(some_complicated_function()) {}
        virtual void foo() override {}
    };

It is invalid, because left and right need to have a constructor that
initializes base (with some_complicated_type). However, left and right are
abstract classes anyway, so they will never initialize their base
themselves, since they inherit from it virtually (and they are never
instantiated directly, but only used as a base to a derived class which
then has the responsibility of initializing the virtual base).

Currently, this requires rather stupid workarounds like:

    struct left : virtual base {
        left() : base(some_unused_dummy_value) {}
        // this dummy value won't ever be used, since 'left' is abstract.
    };
    // And similar for right

Which can be worse than just a slight inconvenience when it is not trivial
to obtain a simple dummy value of some_complicated_type or base. (Which is
probably the case, since base doesn't have a default constructor.

Also, when there are a lot of intermediate abstract classes, this
dummy-value-trick will have to be repeated all over the place.
A way worse solution, but which at leasts prevent repeating dummy values
and dummy constructors would be to add a dummy default constructor to base
which should never be called:

    base() { /* Never call me! No seriously, bad things will happen. */ }

Another way to 'work around' this problem is to add a constructor to left
and right that take some_complicated_type and use it to 'initialize' base
with. But that just pushes the dummy-value problem to the constructor of
derived:

        derived() : base(some_complicated_function()),
                    left(some_unused_dummy_value),
                    right(some_unused_dummy_value) {}

To prevent having to come up with unused dummy values all over the place,
or other stupid workarounds, I propose a minor change to the C++ standard:

*I propose to allow a derived class to not initialize a virtual base. Doing
so would simply make the derived class an abstract class**.
*

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.



------=_Part_61_32559328.1374183533555
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hello,<br><br>Currently, the following code is invalid:<br><br><span style=
=3D"font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; struct base {<b=
r>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; explicit base(some_complicated_type=
);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; virtual void foo() =3D 0; // ba=
se is abstract<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; virtual ~base();<br=
>&nbsp;&nbsp;&nbsp; };<br><br>&nbsp;&nbsp;&nbsp; struct left : virtual base=
 {};<br>&nbsp;&nbsp;&nbsp; struct right : virtual base {};<br><br>&nbsp;&nb=
sp;&nbsp; struct derived : left, right {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;=
&nbsp; derived() : base(some_complicated_function()) {}</span><span style=
=3D"font-family: courier new,monospace;"><span style=3D"font-family: courie=
r new,monospace;"><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; virtual void fo=
o() override {}<br></span>&nbsp;&nbsp;&nbsp; };</span><br><br>It is invalid=
, because left and right need to have a constructor that initializes base (=
with some_complicated_type). However, left and right are abstract classes a=
nyway, so they will never initialize their base themselves, since they inhe=
rit from it virtually (and they are never instantiated directly, but only u=
sed as a base to a derived class which then has the responsibility of initi=
alizing the virtual base).<br><br>Currently, this requires rather stupid wo=
rkarounds like:<br><br><span style=3D"font-family: courier new,monospace;">=
&nbsp;&nbsp;&nbsp; struct left : virtual base {<br>&nbsp;&nbsp;&nbsp; &nbsp=
;&nbsp;&nbsp; left() : base(some_unused_dummy_value) {}<br>&nbsp;&nbsp;&nbs=
p; &nbsp;&nbsp;&nbsp; // this dummy value won't ever be used, since 'left' =
is abstract.<br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; // And similar =
for right</span><br><br>Which can be worse than just a slight inconvenience=
 when it is not trivial to obtain a simple dummy value of some_complicated_=
type or base. (Which is probably the case, since base doesn't have a defaul=
t constructor.<br><br>Also, when there are a lot of intermediate abstract c=
lasses, this dummy-value-trick will have to be repeated all over the place.=
<br>A way worse solution, but which at leasts prevent repeating dummy value=
s and dummy constructors would be to add a dummy default constructor to bas=
e which should never be called:<br><br><span style=3D"font-family: courier =
new,monospace;">&nbsp;&nbsp;&nbsp; base() { /* Never call me! No seriously,=
 bad things will happen. */ }</span><br><br>Another way to 'work around' th=
is problem is to add a constructor to left and right that take some_complic=
ated_type and use it to 'initialize' base with. But that just pushes the du=
mmy-value problem to the constructor of derived:<br><br><span style=3D"font=
-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; deri=
ved() : </span><span style=3D"font-family: courier new,monospace;"><span st=
yle=3D"font-family: courier new,monospace;"><span style=3D"font-family: cou=
rier new,monospace;"><span style=3D"font-family: courier new,monospace;">ba=
se</span></span>(some_complicated_function()),<br>&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp; </span>left(</span><span style=3D"font-family: courier new,m=
onospace;"><span style=3D"font-family: courier new,monospace;">some_unused_=
dummy_value),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right(</span></spa=
n><span style=3D"font-family: courier new,monospace;"><span style=3D"font-f=
amily: courier new,monospace;"><span style=3D"font-family: courier new,mono=
space;">some_unused_dummy_value)</span></span> {}</span><br><br>To prevent =
having to come up with unused dummy values all over the place,<br>or other =
stupid workarounds, I propose a minor change to the C++ standard:<br><br><b=
>I propose to allow a derived class to not initialize a virtual base. Doing=
 so would simply make the derived class an abstract class</b><b>.<br></b><b=
r><br>

<p></p>

-- <br />
&nbsp;<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_61_32559328.1374183533555--

.