In-class definition of pure virtual functions

124 views
Skip to first unread message

Columbo

unread,
Apr 22, 2015, 5:55:32 AM4/22/15
to std-pr...@isocpp.org
Good morning. Is there any technical reason why

virtual void foo() = 0 {};

is not allowed? The grammar can be adjusted, and parsers seem to deal fine with it: VC++ even allows this as an extension.

I'd propose to adjust function-definition to include pure-specifiers. Would such a proposal be successful?

Francis (Grizzly) Smit

unread,
Apr 22, 2015, 6:40:16 AM4/22/15
to std-pr...@isocpp.org


On 22/04/15 19:55, Columbo wrote:
Good morning. Is there any technical reason why

virtual void foo() = 0 {};


what does this mean ??


is not allowed? The grammar can be adjusted, and parsers seem to deal fine with it: VC++ even allows this as an extension.

I'd propose to adjust function-definition to include pure-specifiers. Would such a proposal be successful?
--

--
   .~.     In my life God comes first....
   /V\         but Linux is pretty high after that :-D
  /( )\    Francis (Grizzly) Smit
  ^^-^^    http://www.smit.id.au/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GM/CS/H/P/S/IT/L d- s+:+ a++ C++++ UL++++$ P++ L+++$ E--- W++
N W--- M-- V-- PE- PGP t+ 5-- X-- R- tv b++++ D-
G e++ h+ y?
------END GEEK CODE BLOCK------
http://www.geekcode.com/

Columbo

unread,
Apr 22, 2015, 7:01:52 AM4/22/15
to std-pr...@isocpp.org

Am Mittwoch, 22. April 2015 11:40:16 UTC+1 schrieb Francis Grizzly Smit:


On 22/04/15 19:55, Columbo wrote:
Good morning. Is there any technical reason why

virtual void foo() = 0 {};


what does this mean ??

This defines a pure virtual member function foo.
This syntax could be particularly useful for destructors:

virtual ~MyClass() = 0 = default;

Looks ridiculous, yes, but that is compensated for by not having to provide a definition outside the class one.
 
 

Henrik Vallgren

unread,
Apr 22, 2015, 7:11:54 AM4/22/15
to std-pr...@isocpp.org
Hi,

I don’t see the point in this: the ”=0” part says that you will not provide an 
implementation for this class and then you add an empty one?

Why don’t you use

virtual void foo() {}

Kind regards,
Henrik


--

---
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-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

Andrey Semashev

unread,
Apr 22, 2015, 7:17:28 AM4/22/15
to std-pr...@isocpp.org
On Wednesday 22 April 2015 13:11:48 Henrik Vallgren wrote:
> Hi,
>
> I don’t see the point in this: the ”=0” part says that you will not provide
> an implementation for this class and then you add an empty one?

Pure virtual (= 0) means the function must be defined in the derived class. It
does not mean it must not have a body, although sometimes it _may_ not have
one. Pure virtual destructors, for instance, are possible and must have a
body, but the body must be defined out-of-class currently.

Columbo

unread,
Apr 22, 2015, 7:31:33 AM4/22/15
to std-pr...@isocpp.org
Am Mittwoch, 22. April 2015 12:11:54 UTC+1 schrieb HenrikVallgren:
Hi,

I don’t see the point in this: the ”=0” part says that you will not provide an 
implementation for this class and then you add an empty one?
 
Andrey described it pretty well: The =0 part indicates that this is a pure virtual function. §10.4/2:

A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1).

Henrik Vallgren

unread,
Apr 22, 2015, 7:40:43 AM4/22/15
to std-pr...@isocpp.org

Evidently, I was wrong. The closest I’ve ever come to this was a

software that emitted a “pure virtual function called”-exception.

//Henrik

--

Nevin Liber

unread,
Apr 22, 2015, 10:33:00 AM4/22/15
to std-pr...@isocpp.org
On 22 April 2015 at 06:01, Columbo <r....@gmx.net> wrote:

This defines a pure virtual member function foo.
This syntax could be particularly useful for destructors:

virtual ~MyClass() = 0 = default;

Looks ridiculous, yes, but that is compensated for by not having to provide a definition outside the class one.

Given that every derived class will generate a destructor, this is ridiculous.  Why can't this particular use case (not being able to instantiate the base class) be done today with protected constructors?
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Johannes Schaub

unread,
Apr 22, 2015, 11:35:09 AM4/22/15
to std-pr...@isocpp.org
2015-04-22 16:32 GMT+02:00 Nevin Liber <ne...@eviloverlord.com>:
> On 22 April 2015 at 06:01, Columbo <r....@gmx.net> wrote:
>>
>>
>> This defines a pure virtual member function foo.
>> This syntax could be particularly useful for destructors:
>>
>> virtual ~MyClass() = 0 = default;
>>
>> Looks ridiculous, yes, but that is compensated for by not having to
>> provide a definition outside the class one.
>
>
> Given that every derived class will generate a destructor, this is
> ridiculous. Why can't this particular use case (not being able to
> instantiate the base class) be done today with protected constructors?
>

I am not sure whether this is *the* usecase I have in mind for =0 on
destructors. My prime usecase for it would be to make a class abstract
without having the programmer of the derived class to write an
implementation of the method (the compiler does it itself).
Particularly usable for "marker interfaces". For just preventing
instantiation, abusing "=0" looks a bit like overkill.

Nevin Liber

unread,
Apr 22, 2015, 11:42:13 AM4/22/15
to std-pr...@isocpp.org
On 22 April 2015 at 10:35, Johannes Schaub <schaub....@googlemail.com> wrote:
2015-04-22 16:32 GMT+02:00 Nevin Liber <ne...@eviloverlord.com>:
> On 22 April 2015 at 06:01, Columbo <r....@gmx.net> wrote:
>> virtual ~MyClass() = 0 = default;
> Why can't this particular use case (not being able to
> instantiate the base class) be done today with protected constructors?

I am not sure whether this is *the* usecase I have in mind for =0 on
destructors. My prime usecase for it would be to make a class abstract
without having the programmer of the derived class to write an
implementation of the method (the compiler does it itself).

Again, why don't protected constructors cover this case?  I'm just not seeing it.

Johannes Schaub

unread,
Apr 22, 2015, 11:49:40 AM4/22/15
to std-pr...@isocpp.org
You still need a virtual destructor to have the class be polymorphic
and allow delete through base class ptr. With the "=0" you get both
with only one declaration.

Nevin Liber

unread,
Apr 22, 2015, 11:54:35 AM4/22/15
to std-pr...@isocpp.org
On 22 April 2015 at 10:49, Johannes Schaub <schaub....@googlemail.com> wrote:
> Again, why don't protected constructors cover this case?  I'm just not
> seeing it.
>

You still need a virtual destructor to have the class be polymorphic
and allow delete through base class ptr. With the "=0" you get both
with only one declaration.

That just seems like too tiny a use case for something which we can express today to warrant a language change.

Johannes Schaub

unread,
Apr 22, 2015, 11:59:53 AM4/22/15
to std-pr...@isocpp.org
2015-04-22 17:53 GMT+02:00 Nevin Liber <ne...@eviloverlord.com>:
> On 22 April 2015 at 10:49, Johannes Schaub <schaub....@googlemail.com>
> wrote:
>>
>> > Again, why don't protected constructors cover this case? I'm just not
>> > seeing it.
>> >
>>
>> You still need a virtual destructor to have the class be polymorphic
>> and allow delete through base class ptr. With the "=0" you get both
>> with only one declaration.
>
>
> That just seems like too tiny a use case for something which we can express
> today to warrant a language change.
>

I don't know. Not having to write

class MyBaseClass {
protected:
MyBaseClass();
MyBaseClass(const MyBaseClass&);

public:
virtual ~MyBaseClass();
};

when you can simply write

class MyBaseClass {
virtual ~MyBaseClass() = 0;
};

sounds like a nice use case. And in the second way, you also
*actually* get an abstract class, and not just an approximation of it.

Johannes Schaub

unread,
Apr 22, 2015, 12:04:02 PM4/22/15
to std-pr...@isocpp.org
2015-04-22 17:53 GMT+02:00 Nevin Liber <ne...@eviloverlord.com>:
> On 22 April 2015 at 10:49, Johannes Schaub <schaub....@googlemail.com>
> wrote:
>>
>> > Again, why don't protected constructors cover this case? I'm just not
>> > seeing it.
>> >
>>
>> You still need a virtual destructor to have the class be polymorphic
>> and allow delete through base class ptr. With the "=0" you get both
>> with only one declaration.
>
>
> That just seems like too tiny a use case for something which we can express
> today to warrant a language change.

I don't see that a language change is warranted either.

It should also be noted that a major ABI that at least GCC and Clang
use by default put the Vtable of a class into the TU where the first
virtual function was defined in. So if you write "= 0 = default;" on a
virtual destructor, I can see how this increases link time and each
object file size, because you get multiple redundant vtables for the
same class in the .o files of every derived class that calls that
implicitly defined inline destructor.

So I prefer my virtual destructor to be non-inline.

Andrey Semashev

unread,
Apr 22, 2015, 12:10:31 PM4/22/15
to std-pr...@isocpp.org
I think the original suggestion was to be able to provide an inline body of a
pure virtual function. So the motivating example would be:

class MyBaseClass {
virtual ~MyBaseClass() = 0 {}
};

vs.:

class MyBaseClass {
virtual ~MyBaseClass() = 0;
};

// Assuming we're defining it in a header, it has to be inline
inline MyBaseClass::~MyBaseClass() {}

Whether or not the function is a destructor is irrelevant, the benefit here is
simply a more concise code. IMHO, if there isn't a reason to not allow it, it
would be a nice change.

Nevin Liber

unread,
Apr 22, 2015, 12:12:59 PM4/22/15
to std-pr...@isocpp.org
On 22 April 2015 at 10:59, Johannes Schaub <schaub....@googlemail.com> wrote:
I don't know. Not having to write

class MyBaseClass {
protected:
   MyBaseClass();
   MyBaseClass(const MyBaseClass&);

public:
   virtual ~MyBaseClass();
};

Most non-final polymorphic classes shouldn't have public copy (and don't forget move) constructors anyway, as it is far too easy to slice the object. 
 
when you can simply write

class MyBaseClass {
   virtual ~MyBaseClass() = 0;
};

sounds like a nice use case. And in the second way, you also
*actually* get an abstract class, and not just an approximation of it.

What is the difference between an abstract class and an approximation of an abstract class? Specifically, what can you do with one and not the other?

David Rodríguez Ibeas

unread,
Apr 22, 2015, 12:16:28 PM4/22/15
to std-pr...@isocpp.org
On Wed, Apr 22, 2015 at 5:03 PM, Johannes Schaub <schaub....@googlemail.com> wrote:
It should also be noted that a major ABI that at least GCC and Clang
use by default put the Vtable of a class into the TU where the first
virtual function was defined in. 

That is really to the TU where the first *non-inline* virtual function is defined. In many cases this might be the destructor, but the destructor could also be provided out of the class definition as an inline function and yield the same behavior.

Johannes Schaub

unread,
Apr 22, 2015, 12:19:02 PM4/22/15
to std-pr...@isocpp.org
I did see a lot of code in LLVMt/Clang that did put empty destructors
into their cpp file and I thought I read somewhere that this is
because otherwise it would emit duplicate Vtables because the dtor was
the first virtual function. Seems like I did misread?

David Rodríguez Ibeas

unread,
Apr 22, 2015, 12:29:06 PM4/22/15
to std-pr...@isocpp.org
No, you read correctly. I am just stating that the proposal (which I don't think I buy into) would be equivalent to:

class T {
   virtual ~T() = 0;
};
inline T::~T() {}

That is different from moving the constructor to the .cpp file that will more efficiently build (avoid duplicate vtables, avoid removing the duplicates).  

The comment was trying to raise the point that while closely related (avoid providing all virtual functions inline, where the proposal is helping do exactly that), it is not strictly equivalent. If the class above had a different non-pure virtual function that was not defined inline, the vtable would be generated in the TU that defined that function.

Tony V E

unread,
Apr 22, 2015, 1:57:32 PM4/22/15
to Standard Proposals

--



I think this is perfectly reasonable (although that may be because I've used VC++)  - pure virtual is orthogonal to having an implementation.
Tony

Columbo

unread,
Apr 23, 2015, 6:27:59 AM4/23/15
to std-pr...@isocpp.org, dib...@ieee.org
Let me get this straight. The only (substantial) difference between
struct A1 { virtual void f(); };
and
struct A2 { virtual void f() = 0; }
is that A2 is abstract and derived classes are forced to override and define f to be able to be a most-derived class - right? However, I can provide an in-class definition for A1::foo:
struct A1 { virtual void f(){} };
7.1.2/3 specifies that this is equivalent to
struct A1 { virtual void f(); };
inline void A1::f() {}
So this would cause the same problems as
struct A1 { virtual void f() = 0 {}; };
However, for the sake of consistency, even though in-class definitions might not be optimal - wouldn't it still be feasible to make those available for pure virtual functions?
Assuredly there is a reason that VC++ allows this?

Reply all
Reply to author
Forward
0 new messages