There are many more options available than the two you mentioned, but without details on what you are exactly trying to achieve, it's hard to tailor the answer. I don't know Qt at all, but I have done quite a bit of GUI, so let me give a few "generic" options that you could consider, depending on what your needs are:
1) Composition: basically, you can allow your class (page) to include polymorphic objects to customize it. This would be appropriate if the code in the class (page) has a lot of other stuff that is common to all cases (as you mentioned that the pages are basically the same) and you don't want to copy-paste that code for each new customized page. This option imposes a clear divide between the basic and custom functionality and data. Say, all you need to customize is the response to a button in the page that is clicked:
class ButtonHandler {
public:
virtual void OnClick() = 0;
};
class CustomPage : ... Qt stuff ... {
private:
ButtonHandler* hdlr;
public:
... lots of Qt stuff ...
//give a button handler on construction
CustomPage(ButtonHandler* aHdlr) : hdlr(aHdlr), ... { ... };
//handle the button click
void OnClick() {
if(hdlr)
hdlr->OnClick();
};
};
class HelloWorld : public ButtonHandler {
public:
virtual void OnClick() { Message("Hello World!"); };
};
int main() {
CustomPage page1(new HelloWorld);
...
};
2) Inheritance: have a base (page) class for all the common functionality and provide protected virtual functions for the customizable features. Then, you have a derived class for each special case. This is appropriate if, for the purpose of implementing the special functionality, you need access to data or functions that are within the base (page) class (mainly for reading it, writing it is not as nice). This option imposes a clear divide between the basic and custom functionality but not as strict of a divide between basic and custom data. Reiterating the same example:
class BasicPage : .... Qt stuff .... {
...
protected:
virtual void DerivedOnClick() = 0;
public:
void OnClick() {
DerivedOnClick();
};
};
class HelloWorldPage : public BasicPage {
protected:
virtual void OnClick() {
Message("Hello World!");
};
};
int main() {
HelloWorldPage my_page;
};
3) If it is difficult to divide functionality between basic and custom (which I would say is poor design), then you would have to implement different classes altogether for each object. This has the big problem of not reusing similar code (which can be solved with option 4). Moreover, not reusing similar code is a problem that reaches beyond the simple annoyance of copy-pasting code, because it becomes very difficult to maintain and is error-prone.
4) Generic Programing (using Policy types): now this is much better because you can mix custom functionalities while reusing code and not necessarily imposing a clear divide between the basic and custom functionality. However, it is a bit more advanced. I will not give an example for this, but if you like one, after looking up that programming style, just ask.