Topic: proposal for constructors of abtract classes


Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Wed, 12 Jan 2005 00:49:54 GMT
Raw View
<kanze@gabi-soft.fr> schrieb im Newsbeitrag
news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...
> Gianni Mariani wrote:
> > kanze@gabi-soft.fr wrote:
> > ...
>
> > > As far as I can tell, no proposal is needed. The standard
> > > says that initialization of a virtual base class is from the
> > > most derived class.  If the compiler generates code to try
> > > to initialize controller from the default constructor of
> > > Interface, and Interface is not the most derived class, then
> > > it is an error in the compiler.
>
> > Three compilers gcc 4.0, comeau 4.3.3 and VC++ 7.3 all produce
> > the same diagnostics :
>
> > % /gcc/gcc-4.0-20041128-build/bin/g++ -o xx virt_inhr_vcbug.cpp
> > virt_inhr_vcbug.cpp: In constructor ?Interface::Interface()?:
> > virt_inhr_vcbug.cpp:4: error: ?controller::controller()? is private
> > virt_inhr_vcbug.cpp:22: error: within this context
>
> > I suppose it's time to file a bug on at least these three
> > compilers ?
>
> Yep.


Well, please explain to me.

Okay, the default constructor for the virtual base class is never called -
which you have pointed out more than once in this thread. But what about
name lookup and access control rules? When the constructor of Interface is
parsed, why should it simply forget the fact that controller() is
inaccessible?

FWIW, I don't think it matters if it is ever called:

struct base
{
private:
int foo();
};

class derived : public base
{
derived();
void bar() {foo();}
};


I fail to see how derived::bar could ever be called. Still do you argue
compilers should eat that code happily?

If yes, what part of the Standard allows the example provided by the OP, or
this one? I couldn't find it.


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Wed, 12 Jan 2005 07:36:11 GMT
Raw View
Thomas Mang wrote:
> <kanze@gabi-soft.fr> schrieb im Newsbeitrag
> news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...
>
...
>
> I fail to see how derived::bar could ever be called. Still do you argue
> compilers should eat that code happily?

I think your question is not relevant to the issue.

In my original example, the compiler is accessing a constructor when it
could not possibly be used.  In your example, you're explicitly
accessing a private member function.

The theme behing the C++ language is that you don't have to pay for what
you don't use, so why is there an access to the default constructor when
it can't possibly be used ?

As for the more liberal interpretation that James has applied, I do see
his point.

>
> If yes, what part of the Standard allows the example provided by the OP, or
> this one? I couldn't find it.

I suspect that's the point.  Perhaps it's defect in the standard.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@comAcast.net (Victor Bazarov)
Date: Wed, 12 Jan 2005 15:53:31 GMT
Raw View
Gianni Mariani wrote:
> [...]
> The theme behing the C++ language is that you don't have to pay for what
> you don't use, so why is there an access to the default constructor when
> it can't possibly be used ?

Forgive my possible misunderstanding, but isn't this similar to access
specifiers versus overload resolution?  Why does the Standard make our
compilers include all those private functions into the set of viable
functions when they can never be called just so later the compiler
complains about them being private?  Wouldn't it be better if it were
clever enough to check access specifiers while putting those functions
into the set?

Same thing here.  You want the compiler to figure out that a class cannot
be instantiated, ever, and that its private member can never be called.
Well, that's not how the compiler operates, most likely.  And if we make
the compilers figure out instantiatability of a class in order not to
generate its functions that can never be called, then I insist we do the
same thing with the rest of the rules, starting with overload resolution.

Victor

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Wed, 12 Jan 2005 19:15:24 GMT
Raw View
"Gianni Mariani" <gi2nospam@mariani.ws> schrieb im Newsbeitrag
news:1_udnT3cavl9JXncRVn-pw@speakeasy.net...
> Thomas Mang wrote:
> > <kanze@gabi-soft.fr> schrieb im Newsbeitrag
> > news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...
> >
> ...
> >
> > I fail to see how derived::bar could ever be called. Still do you argue
> > compilers should eat that code happily?
>
> I think your question is not relevant to the issue.


It is IMHO relevant since you presented a specific case of a  more general
topic.


>
> In my original example, the compiler is accessing a constructor when it
> could not possibly be used.  In your example, you're explicitly
> accessing a private member function.


And it cannot be used too since derived::bar can never be called. First,
there is no public constructor of derived. Second, the constructor is not
defined. And third, bar is private, and never called within one of derived's
member functions.
I think that is all enough to guarantee that there is no way to ever invoke
bar.


>
> The theme behind the C++ language is that you don't have to pay for what
> you don't use, so why is there an access to the default constructor when
> it can't possibly be used ?


There is also a theme that the language is clearly defined. Based on that, I
cannot find a paragraph that indicates the compilers you have tested are
buggy. I am not saying there isn't one - but I couldn't find it for my part.
And unless you can present the appropriate para to the compiler
implementers, don't expect your bug report to be accepted.


Take this snippet:

class test{test();};

int main()
{
if (false)
 test();
}


Here, you also never have to pay for a construction of a test (were it that
compiled). But it doesn't matter. The semantics are clearly defined saying
this code is ill-formed.


Same with RVO/NRVO, or binding r-value to reference. In the former case,
some compilers implement it, in the latter I think most (all?) do not create
a copy. Again, it's irrelevant. If there is no copy constructor available,
the code is wrong.


>
> As for the more liberal interpretation that James has applied, I do see
> his point.
>
> >
> > If yes, what part of the Standard allows the example provided by the OP,
or
> > this one? I couldn't find it.
>
> I suspect that's the point.  Perhaps it's defect in the standard.


In my opinion, it is not a defect, it just doesn't say what you like it to
say.

Nevertheless, your complaint should not be ignored. If there is a para in
the STandard that makes your example legal, then you certainly deserve a
price because you have found something a whole bunch of respected compilers
got wrong.
If there isn't, I am sure you can write a proposal making it legal.
However, note that the issue does not apply only to virtual bases classes
alone. Making only that special might well cause more harm than good, and
your proposal should be addressing the more general concept - and if you
still insist on changing only the behavior for the example you gave, I think
including a reasoning and comparison against the other cases would be highly
useful.


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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Wed, 12 Jan 2005 20:39:02 GMT
Raw View
Thomas Mang wrote:
> However, note that the issue does not apply only
 > to virtual bases classes alone.

That's not true. In the general case of abstract classes with
virtual base classes, the C++ standard forces you to write code
which can never be executed. Indeed, if the virtual base class
has no default constructor, it's quite possible that you will
be forced into design contortions to supply a parameter to the
constructor which you do not have available at the abstract
class level, even though this constructor will never be called!

Forcing you to write code which can never be run is different
from checking accessibility of code which you write that can
never be run.

Example:

class BFM;
struct VB { VB(BFM &); };
struct AC : virtual VB { virtual void f() = 0; AC() : VB(???) { } };
struct D : AC { void f(); D(BFM &x) : VB(x) { } };

In AC's constructor, I have no way or need to construct the VB base,
and yet the code will not compile unless I come up with some dummy
way to do it anyway. I suppose I could just write
     AC() : VB(*(BFM *)0) { }
but having to do that seems ridiculous.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Fri, 14 Jan 2005 02:21:45 GMT
Raw View
Victor Bazarov wrote:
> Gianni Mariani wrote:
>
>> [...]
>> The theme behing the C++ language is that you don't have to pay for
>> what you don't use, so why is there an access to the default
>> constructor when it can't possibly be used ?
>
>
> Forgive my possible misunderstanding, but isn't this similar to access
> specifiers versus overload resolution?  Why does the Standard make our
> compilers include all those private functions into the set of viable
> functions when they can never be called just so later the compiler
> complains about them being private?  Wouldn't it be better if it were
> clever enough to check access specifiers while putting those functions
> into the set?

I don't think so.  Consider this:

class X
{
     virtual void F() {}
};

class Y
   : X
{
     public:
     virtual void F() {}
};


Y       y;

int main()
{
     y.F();
}


>
> Same thing here.  You want the compiler to figure out that a class cannot
> be instantiated, ever, and that its private member can never be called.

That's not what I said.

> Well, that's not how the compiler operates, most likely.

In the case I mentioned, it's trivial for the compiler to do so - and,
IMHO, in the ambit of C++ language design tenets.

   And if we make
> the compilers figure out instantiatability of a class in order not to
> generate its functions that can never be called, then I insist we do the
> same thing with the rest of the rules, starting with overload resolution.

I think that's a little overboard.  How do you expect that to work ?


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Fri, 14 Jan 2005 12:34:57 CST
Raw View
"Thomas Mang" wrote:
> <kanze@gabi-soft.fr> schrieb im Newsbeitrag
> news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...
> > Gianni Mariani wrote:
> > > kanze@gabi-soft.fr wrote:
> > > ...

> > > > As far as I can tell, no proposal is needed. The
> > > > standard says that initialization of a virtual base
> > > > class is from the most derived class.  If the compiler
> > > > generates code to try to initialize controller from the
> > > > default constructor of Interface, and Interface is not
> > > > the most derived class, then it is an error in the
> > > > compiler.

> > > Three compilers gcc 4.0, comeau 4.3.3 and VC++ 7.3 all
> > > produce the same diagnostics :

> > > % /gcc/gcc-4.0-20041128-build/bin/g++ -o xx virt_inhr_vcbug.cpp
> > > virt_inhr_vcbug.cpp: In constructor ?Interface::Interface()?:
> > > virt_inhr_vcbug.cpp:4: error: ?controller::controller()? is
private
> > > virt_inhr_vcbug.cpp:22: error: within this context

> > > I suppose it's time to file a bug on at least these three
> > > compilers ?

> > Yep.

> Well, please explain to me.

> Okay, the default constructor for the virtual base class is
> never called - which you have pointed out more than once in
> this thread.  But what about name lookup and access control
> rules? When the constructor of Interface is parsed, why should
> it simply forget the fact that controller() is inaccessible?

Why should it consider access rights to a function which the
compiler says it isn't allowed to call?

> FWIW, I don't think it matters if it is ever called:

> struct base
> {
> private:
> int foo();
> };

> class derived : public base
> {
> derived();
> void bar() {foo();}
> };

> I fail to see how derived::bar could ever be called. Still do
> you argue compilers should eat that code happily?

No, because I wrote the function.  In the case in question, the
compiler is generating the function.  And it is checking the
access rights for a base class function which it is not supposed
to call.

Consider the following:

class Base
{
int foo() ;
} ;

class Derived : public Base
{
} ;

Derived d ;

Should the compiler be allowed to compain that it cannot
generate a constructor for Derived because Base::foo() is
private?

> If yes, what part of the Standard allows the example provided
> by the OP, or this one? I couldn't find it.

The whole point of the exercise is that it isn't there.  That
is, there is no place where the standard says that the compiler
is allowed to check access rights on the default constructor.
All the standard says is that the implicitly defined constructor
should NOT call the constructor for the virtual base class if
the class in question is not the most derived class.  Now, it's
true that the standard doesn't say that the compiler cannot
check access rights on functions it is not allowed to call, but
does it really have to say that?

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Fri, 14 Jan 2005 12:34:46 CST
Raw View
Alberto Barbati wrote:
> kanze@gabi-soft.fr wrote:

> > Given the way g++ generates the constructors, modifying it
> > to suppress the error (but generate a core dump if ever the
> > class is instantiated) should be fairly easy.  (Note too
> > that the fact that the class is abstract is formally
> > irrelevant.  One could imagine, however, that a compiler
> > might want to emit a warning if the class isn't abstract,
> > but suppress it if the class is.)

> I don't think the fact that the class is abstract is formally
> irrelevant.  If the class is abstract, a program attempting to
> instantiate it is ill-formed.  This must (and can) be detected
> at compile-time, you should not (and do not) need to wait till
> link-time to get a diagnostic as you suggested in another
> post.

But that's a quality of implementation issue.  The standard
makes no statement as to when a required diagnostic will occur.
(In fact, failing to provide a function which is needed is
undefined behavior according to the standard -- no diagnostic is
required.  Ever.)

> All the information you need to detect this case are contained
> in the class definition which must be visible at the point of
> instantation.

Why?  If you can't instantiate the "in-charge" constructor,
don't.

If you want, you can even get a pretty good error from the
linker.  If the linker finds an undefined symbol for the
"in-charge" constructor, it looks up the other constructor.  If
it doesn't find it, it gives the normal non-resolved extern
message.  If it finds it, it can easily add something suggesting
the probable cause: that the compiler was unable to generate the
in-charge constructor.

> For what's worth, I find the OP's proposal reasonable.
> However, I can see a weak spot. Let me show it with two
> examples:

>    // Base is the same for both cases
>    class Base
>    {
>    public:
>      Base(int);
>      /* virtual dtor, etc. but no default ctor! */
>    };

>    // case 1: ctor defined out-of-class
>    class Abstract1 : public virtual Base
>    {
>    public:
>       Abstract1();
>       /* virtual dtor, etc. */
>
>       virtual void Method() = 0; // makes class abstract!
>    };

>    // at this point the compiler knows that Abstract1 is
>    // an abstract class, so it cannot be instantiated
>    // "except as sub-objects of a class derived from it." (   10.4/2)

>    Abstract1::Abstract1()
>       // no need to provide a mem-initializer for Base
>       // it will always be ignored (   12.6.2/6)
>    {}

> Currently, you must provide a mem-initializer even if it will
> always be ignored so this code is ill-formed. The proposal
> would make such code legal. I fail to see big problems in
> implementing this case: the compiler has all the information
> it needs when it needs them.

> However, if the ctor is declared in the class body:

>    // case 2: ctor defined in-class
>    class Abstract2 : public virtual Base
>    {
>    public:
>       // is the class abstract at this point?
>       Abstract2() {}

Who cares?  The compiler can't compile it at this point anyway,
since the destructor might (and often will) use member variables
which aren't declared until later.

>       /* virtual dtor, etc. */
>
>       virtual void Method() = 0; // makes class abstract!
>    };

> The compiler now needs to parse the entire class definition to
> determine if the class is abstract before trying to compile
> the ctor. I'm not a compiler expert, but this seems quite a
> bit more difficult than the case above. Maybe the cost is not
> too high, but I have to admit that the advantage of the
> relaxed syntax is not very high either, so it might not be
> worth it.

> PS: in all cases I had to use virtual inheritance, I always
> found a way to have all base classes have public or protected
> default ctors... ;-)

Oh, it's nothing you can't work around.  It's just that you
shouldn't have to.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Fri, 14 Jan 2005 12:35:08 CST
Raw View
Victor Bazarov wrote:
> Gianni Mariani wrote:
> > [...]
> > The theme behing the C++ language is that you don't have to
> > pay for what you don't use, so why is there an access to the
> > default constructor when it can't possibly be used ?

> Forgive my possible misunderstanding, but isn't this similar
> to access specifiers versus overload resolution?  Why does the
> Standard make our compilers include all those private
> functions into the set of viable functions when they can never
> be called just so later the compiler complains about them
> being private?  Wouldn't it be better if it were clever enough
> to check access specifiers while putting those functions into
> the set?

The justification here is that a change in the visibility of a
function in a base class should not change the semantics of the
derived class.  I'm not totally sure I agree -- I have no strong
opinion one way or the other.  But I can understand the
reasoning.

> Same thing here.  You want the compiler to figure out that a
> class cannot be instantiated, ever, and that its private
> member can never be called.

Nobody's asking for that.  In practice, today, as soon as
virtual base classes are involved, the compiler must generate
two constructors.  (In earlier compilers, such as CFront, the
actual choice was made at run-time, using a hidden parameter.)
All I'm really saying is that if there is one of the
constructors which it cannot generate, that it not do so, rather
than generating an error.  Gianni doesn't go quite as far, but
is saying that if it is trivially obvious that one of the two
constructors can never be called, that the compiler not generate
it.

> Well, that's not how the compiler operates, most likely.  And
> if we make the compilers figure out instantiatability of a
> class in order not to generate its functions that can never be
> called, then I insist we do the same thing with the rest of
> the rules, starting with overload resolution.

You might want to check my comments on the error report Gianni
filed with GNU.  At least with g++ or with Sun CC, it would be
relatively easy to implement.

If a compiler uses the CFront strategy, and the class is
actually instantiated, the error will only be detected at
run-time (or might go completely undetected -- which is fine as
far as the standard is concerned, since the error is undefined
behavior).  With g++ or with Sun CC, you would get an error from
the linker.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Fri, 14 Jan 2005 20:39:02 CST
Raw View
"Thomas Mang" wrote:
> "Gianni Mariani" <gi2nospam@mariani.ws> schrieb im Newsbeitrag
> news:1_udnT3cavl9JXncRVn-pw@speakeasy.net...
> > Thomas Mang wrote:
> > > <kanze@gabi-soft.fr> schrieb im Newsbeitrag
> > > news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...

> > ...

> > > I fail to see how derived::bar could ever be called. Still
> > > do you argue compilers should eat that code happily?

> > I think your question is not relevant to the issue.

> It is IMHO relevant since you presented a specific case of a
> more general topic.

> > In my original example, the compiler is accessing a
> > constructor when it could not possibly be used.  In your
> > example, you're explicitly accessing a private member
> > function.

> And it cannot be used too since derived::bar can never be
> called. First, there is no public constructor of
> derived. Second, the constructor is not defined. And third,
> bar is private, and never called within one of derived's
> member functions.  I think that is all enough to guarantee
> that there is no way to ever invoke bar.

> > The theme behind the C++ language is that you don't have to
> > pay for what you don't use, so why is there an access to the
> > default constructor when it can't possibly be used ?

> There is also a theme that the language is clearly
> defined. Based on that, I cannot find a paragraph that
> indicates the compilers you have tested are buggy. I am not
> saying there isn't one - but I couldn't find it for my part.
> And unless you can present the appropriate para to the
> compiler implementers, don't expect your bug report to be
> accepted.

> Take this snippet:

> class test{test();};

> int main()
> {
> if (false)
>  test();
> }

> Here, you also never have to pay for a construction of a test
> (were it that compiled). But it doesn't matter. The semantics
> are clearly defined saying this code is ill-formed.

> Same with RVO/NRVO, or binding r-value to reference. In the
> former case, some compilers implement it, in the latter I
> think most (all?) do not create a copy. Again, it's
> irrelevant. If there is no copy constructor available, the
> code is wrong.

> > As for the more liberal interpretation that James has
> > applied, I do see his point.

> > > If yes, what part of the Standard allows the example
> > > provided by the OP, or this one? I couldn't find it.

> > I suspect that's the point.  Perhaps it's defect in the
> > standard.

> In my opinion, it is not a defect, it just doesn't say what
> you like it to say.

Actually, I'm not really that bothered by the current
situation.  Except that there is a difference between what
compilers actually do, and what the standard says.

> Nevertheless, your complaint should not be ignored. If there
> is a para in the STandard that makes your example legal, then
> you certainly deserve a price because you have found something
> a whole bunch of respected compilers got wrong.

There is a general rule in the standard that the compiler cannot
do just anything, in addition to what it is required to do.  In
the case in point:

1. We are in compiler generated code, not something the
programmer has written.

2. The standard does say that the constructor in question will
NOT call the base class constructor; that this is the
responsibility of the most derived class.

3. The bug we are reporting is that the compiler is generating
an error because the function it is not allowed to call, and
that is never named, is private.

> If there isn't, I am sure you can write a proposal making it
> legal.  However, note that the issue does not apply only to
> virtual bases classes alone. Making only that special might
> well cause more harm than good,

The whole point of the proposal, and of what I consider an error
in all existing compilers, is that virtual base classes ARE
special, in that they are initialized by the most derived class,
and not by the immediate parent (which would result in multiple
initializations).

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Sat, 15 Jan 2005 02:59:10 GMT
Raw View
<kanze@gabi-soft.fr> schrieb im Newsbeitrag
news:1105719280.272294.230270@z14g2000cwz.googlegroups.com...
> "Thomas Mang" wrote:
> > <kanze@gabi-soft.fr> schrieb im Newsbeitrag
> > news:1104935710.586513.123640@z14g2000cwz.googlegroups.com...
> > > Gianni Mariani wrote:
> > > > kanze@gabi-soft.fr wrote:
> > > > ...
>
> > > > > As far as I can tell, no proposal is needed. The
> > > > > standard says that initialization of a virtual base
> > > > > class is from the most derived class.  If the compiler
> > > > > generates code to try to initialize controller from the
> > > > > default constructor of Interface, and Interface is not
> > > > > the most derived class, then it is an error in the
> > > > > compiler.
>
> > > > Three compilers gcc 4.0, comeau 4.3.3 and VC++ 7.3 all
> > > > produce the same diagnostics :
>
> > > > % /gcc/gcc-4.0-20041128-build/bin/g++ -o xx virt_inhr_vcbug.cpp
> > > > virt_inhr_vcbug.cpp: In constructor ?Interface::Interface()?:
> > > > virt_inhr_vcbug.cpp:4: error: ?controller::controller()? is
> private
> > > > virt_inhr_vcbug.cpp:22: error: within this context
>
> > > > I suppose it's time to file a bug on at least these three
> > > > compilers ?
>
> > > Yep.
>
> > Well, please explain to me.
>
> > Okay, the default constructor for the virtual base class is
> > never called - which you have pointed out more than once in
> > this thread.  But what about name lookup and access control
> > rules? When the constructor of Interface is parsed, why should
> > it simply forget the fact that controller() is inaccessible?
>
> Why should it consider access rights to a function which the
> compiler says it isn't allowed to call?
>
> > FWIW, I don't think it matters if it is ever called:
>
> > struct base
> > {
> > private:
> > int foo();
> > };
>
> > class derived : public base
> > {
> > derived();
> > void bar() {foo();}
> > };
>
> > I fail to see how derived::bar could ever be called. Still do
> > you argue compilers should eat that code happily?
>
> No, because I wrote the function.  In the case in question, the
> compiler is generating the function.  And it is checking the
> access rights for a base class function which it is not supposed
> to call.
>
> Consider the following:
>
> class Base
> {
> int foo() ;
> } ;
>
> class Derived : public Base
> {
> } ;
>
> Derived d ;
>
> Should the compiler be allowed to compain that it cannot
> generate a constructor for Derived because Base::foo() is
> private?


No, because the (implicitly defined) constructor never references Base::foo.
That makes it totally different.


>
> > If yes, what part of the Standard allows the example provided
> > by the OP, or this one? I couldn't find it.
>
> The whole point of the exercise is that it isn't there.  That
> is, there is no place where the standard says that the compiler
> is allowed to check access rights on the default constructor.
> All the standard says is that the implicitly defined constructor
> should NOT call the constructor for the virtual base class if
> the class in question is not the most derived class.  Now, it's
> true that the standard doesn't say that the compiler cannot
> check access rights on functions it is not allowed to call, but
> does it really have to say that?

What about 12.6.2/4, which says the entity is default-initialized?
Certainly, the Intermediate constructor never calls the virtual base class
constructor, because it cannot be the most derived class. However, note tha
para4 applies to not listing members in the mem-list, whereas para6 involves
the process of actual initialization. My feeling is para4 is applied before
para6, thus error. The fact the constructor for the virtual base class is
not called at run-time by Intermediate is IMHO just a special
characteristics of vb-initialization, but not for access rights performed at
compile time.
I guess you mean because of para6, the default-initialization call refered
to the virtual base class by para4 is skipped completely, even for access
rights? Well, I think because of clause 11, you'd need special permission
for para4 to do so. And that you clearly not have.
Note also I am not reading para6 meaning access control is transferred to
the most derived class - it is just additional to the most derived class.

But that's just my opinion, and I am not sure.


FYI, you have it the reverse way for destructors.


However, I agree the GCC rejection comment is as useless and irrelevant, as
it can get. That was plain wrong.



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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Mon, 3 Jan 2005 11:34:03 CST
Raw View
Gianni Mariani wrote:
> Since abstract classes cannot be instantiated without being
> derived, any classes inherited virtually in an abstract class
> cannot have their constructor called by the abstract class
> constuctor hence the abstract class constructor must not
> reference the constructor of any virtually inherited class.

> The following code demonstrates the issue:

> class controller
> {
>      controller(); // private don't want anyone to call this
>      public:
>      controller( int ); // this should be called instead
> };

> class Interface
>    : virtual public controller
> {
>      public:
>      virtual void DoThing() = 0;
> };

> class Application
>    : public Interface
> {
>      public:
>      Application()
>        : controller( 3 )
>      {
>      }
>
>      void DoThing()
>      {
>          // Doing it here !
>      }
> };

> The code will issue a diagnostic that the (compiler generated)
> default constructor for Interface is trying to access the
> private controller() constructor. However, even if the
> controller() constructor is made non-private, it is never
> invoked since the most derived class (Application in this
> case) must call the constructor.

> My proposal would make the above example legal C++ since (as
> per the proposal) an abstract class must never reference a
> constructor of a class inherited virtually.

As far as I can tell, no proposal is needed. The standard says
that initialization of a virtual base class is from the most
derived class.  If the compiler generates code to try to
initialize controller from the default constructor of Interface,
and Interface is not the most derived class, then it is an error
in the compiler.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@comAcast.net ("Victor Bazarov")
Date: Tue, 4 Jan 2005 13:17:43 GMT
Raw View
<kanze@gabi-soft.fr> wrote...
> Gianni Mariani wrote:
>> Since abstract classes cannot be instantiated without being
>> derived, any classes inherited virtually in an abstract class
>> cannot have their constructor called by the abstract class
>> constuctor hence the abstract class constructor must not
>> reference the constructor of any virtually inherited class.
>
>> The following code demonstrates the issue:
>
>> class controller
>> {
>>      controller(); // private don't want anyone to call this
>>      public:
>>      controller( int ); // this should be called instead
>> };
>
>> class Interface
>>    : virtual public controller
>> {
>>      public:
>>      virtual void DoThing() = 0;
>> };
>
>> class Application
>>    : public Interface
>> {
>>      public:
>>      Application()
>>        : controller( 3 )
>>      {
>>      }
>>
>>      void DoThing()
>>      {
>>          // Doing it here !
>>      }
>> };
>
>> The code will issue a diagnostic that the (compiler generated)
>> default constructor for Interface is trying to access the
>> private controller() constructor. However, even if the
>> controller() constructor is made non-private, it is never
>> invoked since the most derived class (Application in this
>> case) must call the constructor.
>
>> My proposal would make the above example legal C++ since (as
>> per the proposal) an abstract class must never reference a
>> constructor of a class inherited virtually.
>
> As far as I can tell, no proposal is needed. The standard says
> that initialization of a virtual base class is from the most
> derived class.  If the compiler generates code to try to
> initialize controller from the default constructor of Interface,
> and Interface is not the most derived class, then it is an error
> in the compiler.

Huh?  Am I reading this correctly?  How should the compiler know
that 'Interface' is not the most derived class when it is compiling
the 'Interface' definition?  What if there is no 'Application'
class?  What if its definition is in another compilation unit?

IOW, what are you talking about?

V


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Tue, 4 Jan 2005 14:17:31 GMT
Raw View
Victor Bazarov wrote:
> <kanze@gabi-soft.fr> wrote...
>
...
>>
>>As far as I can tell, no proposal is needed. The standard says
>>that initialization of a virtual base class is from the most
>>derived class.  If the compiler generates code to try to
>>initialize controller from the default constructor of Interface,
>>and Interface is not the most derived class, then it is an error
>>in the compiler.
>
>
> Huh?  Am I reading this correctly?  How should the compiler know
> that 'Interface' is not the most derived class when it is compiling
> the 'Interface' definition?  What if there is no 'Application'
> class?  What if its definition is in another compilation unit?
>
> IOW, what are you talking about?

In this case, "Interface" is an abstract base class which by defintion
cannot be instantiated alone, hence it must be derived which follows, it
cannot possibly reference the virtual base class constructor (or
destructor for that matter).

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Tue, 4 Jan 2005 14:17:47 GMT
Raw View
kanze@gabi-soft.fr wrote:
> Gianni Mariani wrote:
...
>
>>My proposal would make the above example legal C++ since (as
>>per the proposal) an abstract class must never reference a
>>constructor of a class inherited virtually.
>
>
> As far as I can tell, no proposal is needed. The standard says
> that initialization of a virtual base class is from the most
> derived class.  If the compiler generates code to try to
> initialize controller from the default constructor of Interface,
> and Interface is not the most derived class, then it is an error
> in the compiler.

I filed a bug against GCC:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19249

It has been rejected as invalid because the standard says:

"If V does not have an accessible default constructor, the
initialization is ill-formed.  A mem-initializer naming a virtual base
class shall be ignored during execution of the constructor of any class
that is not the most derived class."

The wording here is "ignored".  The question is what "ignored" means.

Clarification anyone ?

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Gianni Mariani <gi2nospam@mariani.ws>
Date: Tue, 4 Jan 2005 08:19:02 CST
Raw View
kanze@gabi-soft.fr wrote:
...
>
>
> As far as I can tell, no proposal is needed. The standard says
> that initialization of a virtual base class is from the most
> derived class.  If the compiler generates code to try to
> initialize controller from the default constructor of Interface,
> and Interface is not the most derived class, then it is an error
> in the compiler.

Three compilers gcc 4.0, comeau 4.3.3 and VC++ 7.3 all produce the same
diagnostics :

% /gcc/gcc-4.0-20041128-build/bin/g++ -o xx virt_inhr_vcbug.cpp
virt_inhr_vcbug.cpp: In constructor    Interface::Interface()   :
virt_inhr_vcbug.cpp:4: error:    controller::controller()    is private
virt_inhr_vcbug.cpp:22: error: within this context

I suppose it's time to file a bug on at least these three compilers ?



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Victor Bazarov <v.Abazarov@comAcast.net>
Date: Tue, 4 Jan 2005 11:23:48 CST
Raw View
Gianni Mariani wrote:
> Victor Bazarov wrote:
>
>> <kanze@gabi-soft.fr> wrote...
>>
> ...
>
>>>
>>> As far as I can tell, no proposal is needed. The standard says
>>> that initialization of a virtual base class is from the most
>>> derived class.  If the compiler generates code to try to
>>> initialize controller from the default constructor of Interface,
>>> and Interface is not the most derived class, then it is an error
>>> in the compiler.
>>
>>
>>
>> Huh?  Am I reading this correctly?  How should the compiler know
>> that 'Interface' is not the most derived class when it is compiling
>> the 'Interface' definition?  What if there is no 'Application'
>> class?  What if its definition is in another compilation unit?
>>
>> IOW, what are you talking about?
>
>
> In this case, "Interface" is an abstract base class which by defintion
> cannot be instantiated alone, hence it must be derived which follows, it
> cannot possibly reference the virtual base class constructor (or
> destructor for that matter).

OK, sorry, James, so the compiler _could_ know, after finishing working
on the entire class that the class is abstract.

Well, the Standard does not make any distinction between constructing
an abstract class object or a concrete class object, AFAICT.  Perhaps
we want to add some kind of relaxation for compiler creators that would
allow them to forgo attempting to instantiate a _virtual_ base class
sub-object in an abstract class.  As always, I have no idea what kind
of difficulties that presents to the implementors.

V

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Wed, 5 Jan 2005 08:37:49 CST
Raw View
Gianni Mariani wrote:
> kanze@gabi-soft.fr wrote:
> > Gianni Mariani wrote:
> ...

> >>My proposal would make the above example legal C++ since (as
> >>per the proposal) an abstract class must never reference a
> >>constructor of a class inherited virtually.

> > As far as I can tell, no proposal is needed. The standard
> > says that initialization of a virtual base class is from the
> > most derived class.  If the compiler generates code to try
> > to initialize controller from the default constructor of
> > Interface, and Interface is not the most derived class, then
> > it is an error in the compiler.

> I filed a bug against GCC:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19249

> It has been rejected as invalid because the standard says:

> "If V does not have an accessible default constructor, the
> initialization is ill-formed.  A mem-initializer naming a
> virtual base class shall be ignored during execution of the
> constructor of any class that is not the most derived class."

Which is a nice case of quoting out of context to get off the
hook:-).  If you read the full paragraph (   12.6.2/6), it is
obvious that this applies only if there is no mem-initializer in
the most derived class.

> The wording here is "ignored".  The question is what "ignored"
> means.

In the text in question, it is obvious.  If I write something
like:

Intermediate::Intermediate()
:   VirtualBase( whatever )
//  ...

the member initializer is ignored unless Intermediate is the
most derived class.

Taken literally, this makes for even more fun: it is legal to
write something like:

Intermediate::Intermediate()
:   VirtualBase( somethingOfATypeVirtualBaseHasNeverHeardOf )
{
}

as long as I never use Intermediate as a most derived class.

Personally, I think we could forego this, as long as leaving the
mem-initializer out works.

Given the way g++ generates the constructors, modifying it to
suppress the error (but generate a core dump if ever the class
is instantiated) should be fairly easy.  (Note too that the fact
that the class is abstract is formally irrelevant.  One could
imagine, however, that a compiler might want to emit a warning
if the class isn't abstract, but suppress it if the class is.)

(BTW: I posted a comment at Bugzilla, but I am not authorized to
change the status, so I don't know that it will be looked at.)

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Wed, 5 Jan 2005 09:50:22 CST
Raw View
"Victor Bazarov" wrote:
> <kanze@gabi-soft.fr> wrote...
> > Gianni Mariani wrote:
> >> Since abstract classes cannot be instantiated without being
> >> derived, any classes inherited virtually in an abstract
> >> class cannot have their constructor called by the abstract
> >> class constuctor hence the abstract class constructor must
> >> not reference the constructor of any virtually inherited
> >> class.

> >> The following code demonstrates the issue:

> >> class controller
> >> {
> >>      controller(); // private don't want anyone to call this
> >>      public:
> >>      controller( int ); // this should be called instead
> >> };

> >> class Interface
> >>    : virtual public controller
> >> {
> >>      public:
> >>      virtual void DoThing() = 0;
> >> };

> >> class Application
> >>    : public Interface
> >> {
> >>      public:
> >>      Application()
> >>        : controller( 3 )
> >>      {
> >>      }
> >>
> >>      void DoThing()
> >>      {
> >>          // Doing it here !
> >>      }
> >> };

> >> The code will issue a diagnostic that the (compiler
> >> generated) default constructor for Interface is trying to
> >> access the private controller() constructor. However, even
> >> if the controller() constructor is made non-private, it is
> >> never invoked since the most derived class (Application in
> >> this case) must call the constructor.

> >> My proposal would make the above example legal C++ since
> >> (as per the proposal) an abstract class must never
> >> reference a constructor of a class inherited virtually.

> > As far as I can tell, no proposal is needed. The standard
> > says that initialization of a virtual base class is from the
> > most derived class.  If the compiler generates code to try
> > to initialize controller from the default constructor of
> > Interface, and Interface is not the most derived class, then
> > it is an error in the compiler.

> Huh?  Am I reading this correctly?  How should the compiler
> know that 'Interface' is not the most derived class when it is
> compiling the 'Interface' definition?

That's its problem, not mine:-).  The standard says that only
the most derived class calls the constructor for a virtual
base.  It also says that I don't have to provide functions which
aren't used.  (Maybe that's not what the authors wanted it to
say, but that's what it says.)

In fact, there are a number of possible solutions.  G++, for
example, generated each constructor twice (more accurately, it
generates two entry points for each constructor): one version is
called from derived class constructors, and the other when the
class is constructed directly.  If for some reason it can't
generate the second one, it could generate some loader record
which would cause an appropriate error message from the loader
if there is an attempt to use it.  (This is, of course, easier
said than done.  Especially in the case of g++, which usually
works with the native linker, over which it has no control.)

> What if there is no 'Application' class?

Then the program has an error.  The error is, in fact, undefined
behavior, so anything the compiler does is legal.  Which means
just generating a call to the address 0 instead of a call to the
non-existant default constructor would be a trivial solution.

>From a QoI point of view, of course, I'd prefer some sort of an
error.  In the case of g++, not generating the
most-derived-class entry point for the constructor would provide
that (although the error message would be rather obscure).

> What if its definition is in another compilation unit?

> IOW, what are you talking about?

What I'm talking about is what the standard requires.  Not how
to implement it:-).  The standard says that the program given is
legal.  Given that, the rest is the compiler writer's problem.
With conventional compiler/linkers of ten or fifteen years ago,
I agree that this would have been a real problem to give an
error message.  (The undefined behavior resulting in a core dump
wouldn't have been difficult even then.)  Today... I doubt that
it is anywhere near as difficult as export, for example.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Wed, 5 Jan 2005 09:50:37 CST
Raw View
Gianni Mariani wrote:
> Victor Bazarov wrote:
> > <kanze@gabi-soft.fr> wrote...

> ...

> >>As far as I can tell, no proposal is needed. The standard
> >>says that initialization of a virtual base class is from the
> >>most derived class.  If the compiler generates code to try
> >>to initialize controller from the default constructor of
> >>Interface, and Interface is not the most derived class, then
> >>it is an error in the compiler.

> > Huh?  Am I reading this correctly?  How should the compiler
> > know that 'Interface' is not the most derived class when it
> > is compiling the 'Interface' definition?  What if there is
> > no 'Application' class?  What if its definition is in
> > another compilation unit?

> > IOW, what are you talking about?

> In this case, "Interface" is an abstract base class which by
> defintion cannot be instantiated alone, hence it must be
> derived which follows, it cannot possibly reference the
> virtual base class constructor (or destructor for that
> matter).

Except that the standard currently requires this to work, even
if the intermediate class is NOT abstract.  If you have an
instance of the intermediate class, you have undefined behavior,
so just generating a call to the address 0 in the place of the
call to the constructor of the virtual base would be conform.
Given what is needed to implement things like export, however, I
imagine that compilers could do better, and given an error
message.  At link time, obviously, since the compiler couldn't
know before then whether the class was used as a most derived
class or not.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Wed, 5 Jan 2005 12:03:12 CST
Raw View
Gianni Mariani wrote:
> kanze@gabi-soft.fr wrote:
> ...

> > As far as I can tell, no proposal is needed. The standard
> > says that initialization of a virtual base class is from the
> > most derived class.  If the compiler generates code to try
> > to initialize controller from the default constructor of
> > Interface, and Interface is not the most derived class, then
> > it is an error in the compiler.

> Three compilers gcc 4.0, comeau 4.3.3 and VC++ 7.3 all produce
> the same diagnostics :

> % /gcc/gcc-4.0-20041128-build/bin/g++ -o xx virt_inhr_vcbug.cpp
> virt_inhr_vcbug.cpp: In constructor ?Interface::Interface()?:
> virt_inhr_vcbug.cpp:4: error: ?controller::controller()? is private
> virt_inhr_vcbug.cpp:22: error: within this context

> I suppose it's time to file a bug on at least these three
> compilers ?

Yep.  They all look like they're trying to be bug compatible
with CFront.  (Given the way CFront handled this case, it would
have been very difficult to do anything but a run-time error if
the intermediate class were instantiated.  I don't know about
Como and VC++, but getting a link-time error if, and only if,
you actually instantiated the intermediate class, would be
simple for g++ or Sun CC.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: AlbertoBarbati@libero.it (Alberto Barbati)
Date: Thu, 6 Jan 2005 03:31:39 GMT
Raw View
kanze@gabi-soft.fr wrote:
>=20
> Given the way g++ generates the constructors, modifying it to
> suppress the error (but generate a core dump if ever the class
> is instantiated) should be fairly easy.  (Note too that the fact
> that the class is abstract is formally irrelevant.  One could
> imagine, however, that a compiler might want to emit a warning
> if the class isn't abstract, but suppress it if the class is.)

I don't think the fact that the class is abstract is formally=20
irrelevant. If the class is abstract, a program attempting to=20
instantiate it is ill-formed. This must (and can) be detected at=20
compile-time, you should not (and do not) need to wait till link-time to=20
get a diagnostic as you suggested in another post. All the information=20
you need to detect this case are contained in the class definition which=20
must be visible at the point of instantation.

For what's worth, I find the OP's proposal reasonable. However, I can=20
see a weak spot. Let me show it with two examples:

   // Base is the same for both cases
   class Base
   {
   public:
     Base(int);
     /* virtual dtor, etc. but no default ctor! */
   };

   // case 1: ctor defined out-of-class
   class Abstract1 : public virtual Base
   {
   public:
      Abstract1();
      /* virtual dtor, etc. */

      virtual void Method() =3D 0; // makes class abstract!
   };

   // at this point the compiler knows that Abstract1 is
   // an abstract class, so it cannot be instantiated
   // "except as sub-objects of a class derived from it." (=A710.4/2)

   Abstract1::Abstract1()
      // no need to provide a mem-initializer for Base
      // it will always be ignored (=A712.6.2/6)
   {}

Currently, you must provide a mem-initializer even if it will always be=20
ignored so this code is ill-formed. The proposal would make such code=20
legal. I fail to see big problems in implementing this case: the=20
compiler has all the information it needs when it needs them.

However, if the ctor is declared in the class body:

   // case 2: ctor defined in-class
   class Abstract2 : public virtual Base
   {
   public:
      // is the class abstract at this point?
      Abstract2() {}

      /* virtual dtor, etc. */

      virtual void Method() =3D 0; // makes class abstract!
   };

The compiler now needs to parse the entire class definition to determine=20
if the class is abstract before trying to compile the ctor. I'm not a=20
compiler expert, but this seems quite a bit more difficult than the case=20
above. Maybe the cost is not too high, but I have to admit that the=20
advantage of the relaxed syntax is not very high either, so it might not=20
be worth it.

Just my though,

Alberto

PS: in all cases I had to use virtual inheritance, I always found a way=20
to have all base classes have public or protected default ctors... ;-)

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gi2nospam@mariani.ws (Gianni Mariani)
Date: Thu, 6 Jan 2005 07:00:51 GMT
Raw View
Alberto Barbati wrote:
...
>
> However, if the ctor is declared in the class body:
>
>   // case 2: ctor defined in-class
>   class Abstract2 : public virtual Base
>   {
>   public:
>      // is the class abstract at this point?
>      Abstract2() {}
>
>      /* virtual dtor, etc. */
>
>      virtual void Method() = 0; // makes class abstract!
>   };
>
> The compiler now needs to parse the entire class definition to determine
> if the class is abstract before trying to compile the ctor. I'm not a
> compiler expert, but this seems quite a bit more difficult than the case
> above. Maybe the cost is not too high, but I have to admit that the
> advantage of the relaxed syntax is not very high either, so it might not
> be worth it.

As the standard applies today, a compiler must be capable of parsing the
entire class before it can generate a constructor (or determine it's
validity).

consider this:

class A { A(); public: A(int); int x; };

class B { public: B(){} /* ... lots o defs */ A a; };

It's not until the compiler reaches the last defintion of the class that
it can determine that B is invalid.

It's certainly not difficult for a compiler to determine a class is
abstract before it needs to generate a constructor in either case given
that it already must parse the entire class before it can do so.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Gianni Mariani <gi2nospam@mariani.ws>
Date: Wed, 29 Dec 2004 12:21:37 CST
Raw View
Since abstract classes cannot be instantiated without being derived, any
classes inherited virtually in an abstract class cannot have their
constructor called by the abstract class constuctor hence the abstract
class constructor must not reference the constructor of any virtually
inherited class.

The following code demonstrates the issue:

class controller
{
     controller(); // private don't want anyone to call this
     public:
     controller( int ); // this should be called instead
};

class Interface
   : virtual public controller
{
     public:
     virtual void DoThing() = 0;
};


class Application
   : public Interface
{
     public:
     Application()
       : controller( 3 )
     {
     }

     void DoThing()
     {
         // Doing it here !
     }
};

The code will issue a diagnostic that the (compiler generated) default
constructor for Interface is trying to access the private controller()
constructor.  However, even if the controller() constructor is made
non-private, it is never invoked since the most derived class
(Application in this case) must call the constructor.

My proposal would make the above example legal C++ since (as per the
proposal) an abstract class must never reference a constructor of a
class inherited virtually.


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]