Aber die Methode fill() ist doch bereits in Mask deklariert (virtual) und wird von den Subklassen nur anders implementiert.

D.h. der Aufruf in MainWidget::loadDocument() wird bereits durch den Polymorphismus auf den jeweiligen Code umgeleitet.

Code:
Mask *mask = new RecipeMask;

mask->fill(...); // Aufruf von RecipeMask::fill();

mask = new BookMask;

mask->fill(...); // Aufruf von BookMask::fill();
Für den Aufruf von fill() ist es bedeutungslos auf welche Subklasse mask gerade veweißt, zur Laufzeit wird die Implementierung der jeweiligen Subklasse ausgeführt.

Wenn wir diesen Codeschnippsel kurz umschreiben
Code:
switch (doctype) {
    case RECIPE:
        mask = new RecipeMask;
        break;

    case BOOK:
        mask = new BookMask;
        break;
}

mask->fill(...);
dann ist im Falle von doctype == RECIPE in der letzten Zeile ein Aufruf von RecipeMask::fill(), im Falle von doctype == BOOK ein Aufruf von BookMask::fill(), usw.

Ciao,
_