Pure virtual functions may not have an inline definition. Why?
Asked Answered
H

5

65

Pure virtual functions are those member functions that are virtual and have the pure-specifier ( = 0; )

Clause 10.4 paragraph 2 of C++03 tells us what an abstract class is and, as a side note, the following:

[Note: a function declaration cannot provide both a pure-specifier and a definition —end note] [Example:

struct C {
virtual void f() = 0 { }; // ill-formed
};

—end example]

For those who are not very familiar with the issue, please note that pure virtual functions can have definitions but the above-mentioned clause forbids such definitions to appear inline (lexically in-class). (For uses of defining pure virtual functions you may see, for example, this GotW)

Now for all other kinds and types of functions it is allowed to provide an in-class definition, and this restriction seems at first glance absolutely artificial and inexplicable. Come to think of it, it seems such on second and subsequent glances :) But I believe the restriction wouldn't be there if there weren't a specific reason for that.

My question is: does anybody know those specific reasons? Good guesses are also welcome.

Notes:

  • MSVC does allow PVF's to have inline definitions. So don't get surprised :)
  • the word inline in this question does not refer to the inline keyword. It is supposed to mean lexically in-class
Homocyclic answered 13/11, 2010 at 21:8 Comment(21)
Looks a bit weird when using a function try block: virtual void f() = 0 try { } catch(...) { }Ornament
Here's a guess: It was simpler to create a compiler that didn't allow it and given its very rare usage, was an easy decision. The fact that some compilers (you cited MSVC) do allow it simply means that some compiler authors weren't bothered by the extra work.Philipp
@Johannes: What's weird about it? Function try blocks are themselves weird :)Homocyclic
@Tergiver: I just don't see why would that make it harder to write compilers?Homocyclic
@Johannes: There weren't even exceptions when this was decided, let alone function try blocks!Microbarograph
I don't think it would be any harder.Ornament
@Downvoter: The question is subjective and argumentative? Not a real question? Poorly formatted/formulated? Let me know so I can improve to meet your high standardsHomocyclic
Of course it's 'harder'. It's an additional notation that has to be allowed on a function declaration construct. Granted, it's not all that difficult, but work not done is time saved, no matter how great or small the value. Anyhow, I didn't say it was a good guess, just a guess.Philipp
Why couldn't the inline syntax be virtual void f() { } = 0;? I'm going to go with the "given the = 0 syntax, any syntax for this would look awkward" theory. Of course if it was just pure virtual void foo() { } or similar it would be fine. But that would require yet another keyword.Discord
You should try asking this on comp.std.c++ or on comp.lang.c++.moderatedKroo
@Martin: I have tried it, twice, to post it to comp.lang.c++.moderated and guess what, I received no answer whatsoever, neither about accepting the post nor about rejecting it.Homocyclic
@Armen: Did you try via google groups or via a "real" newsserver? IIRC there have been some problems with google groups and the moderation process. If you need a NNTP server: try eternal-september dot org -- that works fine for me for the C++ NGsKroo
@Armen, I took time to think about it, maybe I'm too much touchy on this issue so: I still dislike pure virtual functions with a provided implementation. Thus I really like the fact that GotW has named their article (Im)pure Virtual Functions. :-) However glad to knows it exists if I happen to stumble against that. +1 for the question.Aqaba
@Armen, and most of it all: it would be nice if you could find the statement in the standard that would clearly say "Pure Virtual Functions can have an implementation".Aqaba
@Stephane: In the same clause and paragraph I provided there is a phrase "A pure virtual function need be defined only if explicitly called with a qualified-id syntax". Which obviously means it can be definedHomocyclic
@Armen, this word obviously still strongly fight against my reason :-) and I will have to work for understanding that "only if explicitly called with a qualified-id syntax"... Over my limited knowledge.Aqaba
Does this mean MSVC allowing an inline definition for a pure function, while seemingly straightforward and obvious, is actually a non-standard extension?Scalping
@Ashleys: Yes, an extension which stays there even if "Disable Language Extensions" is setHomocyclic
@Armen: re your problem: when you post to [comp.lang.c++.moderated] you should receive an e-mail verification with article number, automatically. unless you're posting with a fake mail address (see the mod guidelines for how to post with valid address yet not having that address propagated to Usenet). use the article number in any correspondence with the moderators. for more information see the web page linked to in the banner at the end of every article. cheers & hth.,Fuddyduddy
You can of course add the definition lower down in the header thus use the word inline in the declaration and define the body after the class. I assume you are concerned about the syntax and not whether you can actually inline them.Bookshelf
up'd mostly for the GotW reference! Perhaps rare, but very interesting use-cases to ponder. Shame I, like others, seem unable to understand how the accepted answer supposedly explains why an inline definition is disallowed. I suspect that, instead, as per other answers, this is just an issue of esoteric, non-extensible syntax and "well, that's just how it is now".Cupel
F
54

In the SO thread "Why is a pure virtual function initialized by 0?" Jerry Coffin provided this quote from Bjarne Stroustrup’s The Design & Evolution of C++, section §13.2.3, where I've added some emphasis of the part I think is relevant:

The curious =0 syntax was chosen over the obvious alternative of introducing a new keyword pure or abstract because at the time I saw no chance of getting a new keyword accepted. Had I suggested pure, Release 2.0 would have shipped without abstract classes. Given a choice between a nicer syntax and abstract classes, I chose abstract classes. Rather than risking delay and incurring the certain fights over pure, I used the tradition C and C++ convention of using 0 to represent "not there." The =0 syntax fits with my view that a function body is the initializer for a function and also with the (simplistic, but usually adequate) view of the set of virtual functions being implemented as a vector of function pointers. [ … ]

So, when choosing the syntax Bjarne was thinking of a function body as a kind of initializer part of the declarator, and =0 as an alternate form of initializer, one that indicated “no body” (or in his words, “not there”).

It stands to reason that one cannot both indicate “not there” and have a body – in that conceptual picture.

Or, still in that conceptual picture, having two initializers.

Now, that's as far as my telepathic powers, google-foo and soft-reasoning goes. I surmise that nobody's been Interested Enough™ to formulate a proposal to the committee about having this purely syntactical restriction lifted, and following up with all the work that that entails. Thus it's still that way.

Fuddyduddy answered 18/11, 2010 at 14:59 Comment(7)
Wow... 21 votes (so far), and unless I've missed something, you've said not one word to address the question (which was actually why out-of-line definitions are possible but inline not).Turgite
@Tony: I'm sorry that you didn't understand the relevance of my answer. I tried my best. It didn't work for you. I don't know how to say it more clearly. Possibly there's a communication gap between us.Fuddyduddy
having 8 hours to ponder, I see that in the narrow context of the site of = 0 what you're saying is coherent. My confusion stems from your not having related that to the out-of-line definition or explored why the above thinking/logic/perspective might not have resulted in a ban on a body definition there, or the realisation of a use for out-of-line definition changed the thinking re in situ definition. This inconsistency is the heart of the question. If there's still a communication gap between us, then I guess we've both done our best - no harm done :-).Turgite
If only he had moved the =0 though to immediately after the word virtual it would have worked so virtual =0 void func() { // code }; Puts the =0 in the place where you probably want it too (i.e. next to virtual) albeit the syntax looks funny.Bookshelf
Like Tony said, it seems like you've answered the question "Pure virtual functions may not have any definition. Why?" and not the question "Pure virtual functions may not have an inline definition (even though they may have an out-of-line definition). Why?"Communalize
@Bookshelf It'll look funny now since we're so used to seeing it the other way round.Settler
@TonyD: Subtly answering the OP's question is the part which goes It stands to reason that one cannot both indicate “not there” and have a body – in that conceptual picture; but I'm not that convinced either.Settler
R
8

You shouldn't have so much faith in the standardization committee. Not everything has a deep reason to explain it. Something are so just because at first nobody thought otherwise and after nobody thought that changing it is important enough (I think it is the case here); for things old enough it could even be an artifact of the first implementation. Some are the result of evolution -- there was a deep reason at a time, but the reason was removed and the initial decision wasn't reconsidered again (it could be also the case here, where the initial decision was because any definition of the pure function was forbidden). Some are the result of negotiation between different POV and the result lacks coherence but this lack was deemed necessary to reach to consensus.

Roar answered 14/11, 2010 at 9:48 Comment(5)
According to D&E, pure virtuals were added to C++ by Stroustrup, after discussing it with in-house C++ users at AT&T, as the last thing merely weeks before the release of cfront 2.0, which shipped in June 1989. By the same source, the first meeting of ANSI X3J16 (which later joined with ISO WG21 to form what we now know as the Standard Committee) took place half a year later, in December 1989. (I thought I had read a reason for not allowing inline definitions for abstract functions, but I couldn't find it in D&E.) So this was not decided by the Standard Committee.Microbarograph
@AProgrammer: Thanks for a good guess. But I am still going to wait for an answer beginning with "So, yeah, I called Bjarne today, and he said ..." :)Homocyclic
So, yeah, I called Bjarne today, but he didn't pick up. ;-)Materiel
@Armen I don't think this is the kind of question to bother Bjarne with. Cheers,Fuddyduddy
@David: Over the last 15 years, I have bothered him with maybe half a dozen emails regarding C++. And he always responded, and very timely, too. I suspect that such a question as Armen's might daily arrive in his inbox by the dozens, so it might not get answered. But I would not outright dismiss the idea.Microbarograph
T
7

Good guesses... well, considering the situation:

  • it is legal to declare the function inline and provide an explicitly inline body (outside the class), so there's clearly no objection to the only practical implication of being declared inside the class.
  • I see no potential ambiguities or conflicts introduced in the grammar, so no logical reason for the exclusion of function definitions in situ.

My guess: the use for bodies for pure virtual functions was realised after the = 0 | { ... } grammar was formulated, and the grammar simply wasn't revised. It's worth considering that there are a lot of proposals for language changes / enhancements - including those to make things like this more logical and consistent - but the number that are picked up by someone and written up as formal proposals is much smaller, and the number of those the Committee has time to consider, and believes the compiler-vendors will be prepared to implement, is much smaller again. Things like this need a champion, and perhaps you're the first person to see an issue in it. To get a feel for this process, check out http://www2.research.att.com/~bs/evol-issues.html.

Turgite answered 24/11, 2010 at 2:54 Comment(0)
W
2

Good guesses are welcome you say?

I think the = 0 at the declaration comes from having the implementation in mind. Most likely this definition means, that you get a NULL entry in the RTTI's vtbl of the class information -- the location where at runtime addresses of the member functions of a class are stored.

But actually, when put a definition of the function in your *.cpp file, you introduce a name into the object file for the linker: An address in the *.o file where to find a specific function.

The basic linker then does need to know about C++ anymore. It can just link together, even though you declared it as = 0.

I think I read that it is possible what you described, although I forgot the behaviour :-)...

Wittie answered 22/11, 2010 at 20:27 Comment(0)
B
0

Leaving destructors aside, implementations of pure virtual functions are a strange thing, because they never get called in the natural way. i.e. if you have a pointer or reference to your Base class the underlying object will always be some Derived that overrides the function, and that will always get called.

The only way to actually get the implementation to be called is using the Base::func() syntax from one of the derived class's overloads.

This actually, in some ways, makes it a better target for inlining, as at the point where the compiler wants to invoke it, it is always clear which overload is being called.

Also, if implementations for pure virtual functions were forbidden, there would be an obvious workaround of some other (probably protected) non-virtual function in the Base class that you could just call in the regular way from your derived function. Of course the scope would be less limited in that you could call it from any function.

(By the way, I am under the assumption that Base::f() can only be called with this syntax from Derived::f() and not from Derived::anyOtherFunc(). Am I right with this assumption?).

Pure virtual destructors are a different story, in a sense. It is used as a technique simply to prevent someone creating an instance of the derived class without there being any pure virtual functions elsewhere.

The answer to the actual question of "why" it is not permitted is really just because the standards committee said so, but my answer sheds some light on what we are trying to achieve anyway.

Bookshelf answered 3/1, 2013 at 12:12 Comment(1)
that assumption about not being able to call it from Derived::anyOtherFunc() is incorrectEpigrammatist

© 2022 - 2024 — McMap. All rights reserved.