8

C++03 3.2.2 ...An object or non-overloaded function is used if its name appears in a potentially-evaluated expression. A virtual member function is used if it is not pure...

And then later in 3.2.3 we have: Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is used.

Along the lines I am reading: a pure virtual function is not used. The ODR applies only to functions which are used. Doesn't this imply that the following would be legal? I am guessing the answer is no, it doesn't, but then I can't understand why.

//x.h
struct A
{
   virtual void f() = 0;
};

//y.cpp
#include "x.h"
void A::f()
{
}

//z.cpp
#include "x.h"
#include <iostream>
void A::f()
{
   std::cout << "Hello" << std::endl;
}

//main.cpp
#include "x.h"
struct B:A
{
   virtual void f()
   {
      A::f();
   }
};

int main()
{
   A* p = new B;
   p->f();
}
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • Does this compile/link ? I feel like there would be a link error, because of a dupllicate struct A implementation. – Stephane Rolland Nov 10 '10 at 15:18
  • @Rolland: what do you mean? A class definition may and should appear in every translation unit in which the class is used... – Armen Tsirunyan Nov 10 '10 at 15:22
  • @Armen, okay, it may appear everywhere, but not several times. In the example there are TWO implementation of A::f(); in y.cpp and in z.cpp – Stephane Rolland Nov 10 '10 at 15:25
  • Seems you indeed found a hole in the standard: the standard doesn't mention if and when pure virtual functions are used. – Philipp Nov 10 '10 at 15:34
  • 1
    @Stephane Rolland: Read the standard again: "Every program shall contain exactly one definition of every non-inline function [...] that is used in that program" and "A virtual member function is used if it is not pure". That means that if a virtual member function is pure, the standard may be interpreted such that it is not used, which would allow arbitrarily many definitions. – Philipp Nov 10 '10 at 15:36
  • 1
    The GCC linker indeed gives an error (even without `main.cpp`), but that is not clear from the standard or even wrong, depending on the meaning of `if`. – Philipp Nov 10 '10 at 15:39
  • I don't understand the standard your way. What arguments makes you state: "arbitrarily many definitions" ? – Stephane Rolland Nov 10 '10 at 15:46
  • 2
    @Stephanie: I think we all agree this example is against the intent of the Standard and it's fine and well that it does cause problems. The discussion is about whether the wording of the Standard accidentally forgot to cover this case. – aschepler Nov 10 '10 at 16:06
  • Ok, and what is Armen code about ? `struct A { virtual void f() = 0; }; //y.cpp #include "x.h" void A::f() { }` **He is implementing a pure virtual function. Worst of all: he does this twice.** – Stephane Rolland Nov 10 '10 at 19:35
  • You may all agree on words and concepts you don't understand well. (well it's what i understand at my level :-) ) – Stephane Rolland Nov 10 '10 at 19:37
  • @Stephane Rolland: While providing two definitions for any non-inline function is not correct, what's so bad about implementing a pure virtual function? – CB Bailey Nov 10 '10 at 19:55
  • @Charles that's maybe the point where I'm limited. For me ( and I am not the Standard okay don't get me this way ;-) ) a pure member function must not have any implementation, since it is **pure** virtual. – Stephane Rolland Nov 10 '10 at 19:58
  • @Stephane Rolland: I think that you've misunderstood what pure virtual means. All it means is that you cannot instantiate a class that which doesn't have a non-pure final overrider for every function which is pure virtual in any direct or indirect base class. A pure virtual function doesn't have to have an implementation if it is not used but it can have one - and must have one if used. – CB Bailey Nov 10 '10 at 20:03
  • @Stephane. Actually it is perfectly OK to provide a definition for a PVF. And there are valid reasons to do so too. see, for example, http://stackoverflow.com/questions/2089083/pure-virtual-function-with-implementation – Armen Tsirunyan Nov 10 '10 at 20:06
  • @Charles and @Armen. Okay I have to ponder about that link. Thanx for the link. In my mind, pure virtual and abstract were so close... Sorry for the bother. I'll come back if I have anything to add ;-) – Stephane Rolland Nov 10 '10 at 20:10
  • Maybe that's not the place to answer me, maybe just a link, but why declaring a member function pure virtual any sense if it is to give it an implementation ? ? ? What does it bring ? – Stephane Rolland Nov 10 '10 at 20:12
  • @Stephane: For example - you want to make your class abstract but it has no pure virtual functions. What do you do? Right, you make the destructor pure virtual. But a destructor HAS to have a definition. Another scenario. Your method is the only virtual method and it's pure virtual. But it would be nice to provide a default implementation which the subclasses may call among doing additional things. – Armen Tsirunyan Nov 10 '10 at 20:17
  • wow I'm completely outleveled... Never did I see a pure virtual destructor. – Stephane Rolland Nov 10 '10 at 20:41

5 Answers5

11

The two clauses are not mutually exclusive. That a virtual function is used if it is not pure, does not mean that the converse holds. If a virtual function is pure it does not mean that it is necessarily not used. It may still be used "if its name appears in a potentially evaluated expression" such as in your example: A::f();.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Erm... I'm still not convinced. The term used is defined via the notion of "potentially evaluated expression" and there's an exception for pure virtual functions. So A::f() is as much a potentially evaluated expression as x->f(); but the latter doesn't mean the function is used... – Armen Tsirunyan Nov 10 '10 at 15:40
  • Let's look at @Steve M's quote: A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1)." If they had added. In this case the pure virtual function is said to be used, everything would be fine. But they haven't :) – Armen Tsirunyan Nov 10 '10 at 15:41
  • 1
    3.2p2 makes no sense unless read as though meeting any of the individual requirements makes a symbol used. For example, an allocation function is used by a new-expression. But it's certainly also used if explicitly called using `operator new`. – aschepler Nov 10 '10 at 15:58
  • 2
    @Armen Tsirunyan: Read the clause carefully again. There's no exception for pure virtual functions; the exception is for non-pure virtual functions which are automatically _used_ whether or not they are also _used_ in any other way. – CB Bailey Nov 10 '10 at 16:08
  • @Charles: You mean if there is a non-pure virtual function, it HAS to be defined whether or not it is, say, called from anywhere? Oh, right, that makes sense... – Armen Tsirunyan Nov 10 '10 at 16:20
  • 1
    @Armen Tsirunyan: Yes. There is a practical reason: in many C++ implementations, the address of such a function needs to be put into the vtable of any object that derives from the class that doesn't override the function. Such a class might be defined only in another translation unit compiled later so it is simplest for the implementations if such a function is counted as _used_ in all cases so the implementation can depend on being able to find the function at link time. Pure virtual functions must be overridden in any instantiable class, so this isn't a concern for them. – CB Bailey Nov 10 '10 at 16:28
  • 1
    @Armen has a point wrt `p->f()`. This actually would make the pure virtual function being used, but it's not intended to be so, of course. However there is already an issue report at http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1174 about this. – Johannes Schaub - litb Nov 28 '10 at 18:25
  • @litb: I very deliberately avoided making any judgement of whether `x->f()` uses the pure virtual function; I didn't need to to answer the original question. ;) – CB Bailey Nov 28 '10 at 18:39
3

This code violates ODR. A::f is multiply defined. Hence it has UB.

Multiple definitions across translation units are only allowed for the following as per $3.2/5

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
1

As @Charles Bailey pointed out, your A::f is in fact used even though it's pure virtual. But that's beside the main point.

It's not accurate that the One Definition Rule does not apply to functions that are not used. We have:

3.2p1 No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.

3.2p3 Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required.

Together, these requirements seem to imply that a used function must have exactly one definition, and an unused function (including a pure virtual function which is never explicitly called) may have either no definition or a single definition. In either case, multiple definitions for a non-inline function makes the program ill-formed.

At least, I'm quite certain that's the intent. But you may be on to a hole in the phrasing, since a very literal reading does not say anywhere that multiple different definitions of the same unused function in different translation units is ill-formed.

// x.cpp
void f() {}
void g() {}

// y.cpp
#include <iostream>
void f() {
  std::cout << "Huh" << std::endl;
}
void h() {}

// z.cpp
void g();
void h();
int main() { 
  g();
  h();
  return 0;
}
Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • No wait, 3.2p1 does say "translation unit". I think there may in fact be a phrasing hole. – aschepler Nov 10 '10 at 15:55
  • 3.2/1 is not phrasing hole. It applies to inline functions, classes and enumerations that are allowed to be defined once _per translation unit_, unlike non-inline functions and objects. – CB Bailey Nov 10 '10 at 16:16
  • @Charles: Agreed. But what requirement says that my sample program is ill-formed? Paragraph 1 doesn't apply since the definitions are in different translation units. P2 does not say `f()` is used. P3 doesn't apply because it's not used. P4 is about class definitions. P5 is about things including inline functions which really can be multiply defined. – aschepler Nov 10 '10 at 16:33
  • I think that it is _supposed_ to be 3.2/5, which describes exactly which entities _may_ have more than one definition in a program and the restrictions on multiple definitions. I'll admit that it's only by implication that if the entity isn't on the list that it may not have more than one definition in the program (i.e. only zero or one definitions). – CB Bailey Nov 10 '10 at 16:45
  • I posted this some time ago to usenet, and it was found it's a defect. But I didn't post it to the committee as an issue report. You may wish to do so. – Johannes Schaub - litb Nov 28 '10 at 18:30
1

This is related but off-topic: from the citations it seems there is a hole in the Standard alright: it should also say a pure virtual destructor is used, and, that it must be defined; at least if there exist any derived class objects which are destroyed or if a destructor of such is defined, since the derived class destructor must call the base destructor, implicitly it does so with the qualified::id syntax. The definition of such destructors is usually trivial but cannot be elided and cannot be generated.

Yttrill
  • 4,725
  • 1
  • 20
  • 29
  • 12.4p7: "A destructor can be declared `virtual` (10.3) or pure `virtual` (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined." (My note: 'objects' includes member subobjects.) – aschepler Nov 29 '10 at 19:34
0

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

Your A::f is called by B::f, so there must be a single definition of A::f.

Steve M
  • 8,246
  • 2
  • 25
  • 26