[Development] final value classes: some background information and plans

Marc Mutz marc.mutz at kdab.com
Wed Mar 7 08:57:03 CET 2012


Hi,

I've uploaded a patch series that makes most of the value classes in QtCore 
final in the C++11 sense (ie. under a C++11 compiler, these can no longer be 
inherited from). The changesets, for reference, are
  http://codereview.qt-project.org/19008
thu
  http://codereview.qt-project.org/19024

This is a source-incompatible change, but like adding explicit to 
constructors, it's one that only affects code that shouldn't have been 
written like that in the first place, and thus makes Qt a slightly safer 
place to be.

Value classes are meant to be be used as-is. When they are subclassed, that 
usually indicates laziness on the side of the programmer in the best case, 
and a deep misunderstanding of C++' class model in the worst case. Of the 
instances I fixed in qtbase, only the QtDBus one was actually safe, since it 
used private inheritance. It was also the easiest to fix, since private 
inheritance is not much different from private composition.

The notable absentees from this patch are the containers. I do intend to make 
these final, too, but they're not included in this patch series, for two 
reasons: 1. they tend to be inherited from a lot, including in the public Qt 
API, and 2. I'd submit these against the container branch, not api_changes. I 
plan to deal with the inheritance in public API by renaming QContainer into 
QBasicContainer, with protected construction and destruction, and then 
inheriting QContainer from them as final classes. Public classes that inherit 
from containers (QPolygon, QStringList, ...) would then have to inherit from 
QBasicContainer. In the next step, this would allow QList to select the most 
efficient backend to use (QBasicList or QBasicVector), depending on the 
QTypeInfo traits. This would deal with the inefficiencies surrounding 
QList<T> where sizeof(T) != sizeof(void*) or T isn't movable in a SC way.

It's a pity that final will only be interpreted by a C++11 compiler, but I 
have a patch pending that uses MSVCs non-standard 'sealed' extension to back 
Q_DECL_FINAL{,_CLASS} on MSVC >= 2005, so at least on Windows, these will 
trigger immediately (and VC11 is supposed to have explicit virtual override 
with C++11 syntax). Most projects probably at least occasionally compile on 
Windows, too, so marking classes are final promises to be an effective tool 
to prevent these design mistakes.

That said, for the MSVC use case, I'll need to make qglobal.h not clobber 
Q_DECL_{OVERRIDE,FINAL{,_CLASS}} if they're already set, so for porting, an 
easy workaround will be to define Q_DECL_FINAL_CLASS to nothing in the build 
system, and the compiler will happily shut up and let you do your thing.

As a by-product of these changes, I could remove the vtable from QDataStream 
and QDirIterator.

Any feedback is greatly appreciated.

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
www.kdab.com || Germany +49-30-521325470 || Sweden (HQ) +46-563-540090
KDAB - Qt Experts - Platform-Independent Software Solutions



More information about the Development mailing list