2

Is it a good idea to enable the final C++11 keyword conditionally to the standard version in a header file? I'm thinking of something like:

#if __cplusplus >= 201103L
#   define MY_FINAL final
#else
#   define MY_FINAL
#endif

// ...

class Derived : public Base
{
public:
    virtual int f() MY_FINAL;
};  

I have two doubts here:

  1. whether the method with and without final will be ABI-compatible (it seems reasonable to assume so to me, and a quick check with g++ confirms that),
  2. that the C++98 compiler won't complain when someone tries to override the method. But I believe that documenting the method as don't override it should handle this.
Xeo
  • 129,499
  • 52
  • 291
  • 397
Michał Górny
  • 18,713
  • 5
  • 53
  • 76

2 Answers2

3

1) final should never affect the ABI, it only affects whether the translation from C++ source code should succeed or fail, it has no required effect on the generated code.

2) You can make the compiler complain even in C++98 mode if you are prepared to use some non-standard extensions. G++ 4.7 supports __final in C++98 mode with the same meaning:

#if __cplusplus >= 201103L
#   define MY_FINAL final
#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#   define MY_FINAL __final
#else
#   define MY_FINAL
#endif

I think clang++ accepts final in C++98 mode, but issues a warning.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 2
    `it only affects whether the translation from C++ source code should succeed or fail, it has no affect on the generated code.` I believe it provides an optimization opportunity as well, thus affecting the generated code. Well, unless you meant only the implementation and not the caller code. – Michał Górny Aug 13 '12 at 20:51
  • Yes, you're completely right. I should have said it has no effect on the ABI, and no _required_ effect on the code - optimisations that don't change the meaning are allowed. – Jonathan Wakely Aug 13 '12 at 21:28
1

#2 is pretty given. I'm not so sure about #1, though. Logically, the C++11 compiler is well within it's rights to inline calls to f() on a Derived object, for example, and not issue a virtual call, whereas a C++03 compiler is compelled to issue a virtual call. I'm not sure if this will actually make any difference, but it might.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    Apart from being faster it makes no difference that users can detect, and so under the "as if" rule C++03 compilers are not obliged to make a virtual call when the final overrider is known e.g. when the dynamic type of the object is known. In any case, that doesn't affect the ABI. – Jonathan Wakely Aug 13 '12 at 20:35
  • If a `Derived*` was pointing to a class in C++03 which did override this function, the C++11 compiler would not call the more derived version and the C++03 compiler would. – Puppy Aug 14 '12 at 09:13
  • How would the more-derived class override it? That code would not compile in C++11. And the case I gave is where the dynamic type is known, so the compiler knows which override is the final overrider. – Jonathan Wakely Aug 14 '12 at 13:44