[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