2

Since Qt doesnt allow templates in their slots, I tried to do the following solution without success.

First a would like to create a list like this:

list commands = 
0, "MyDashboard", DashBoard0
1, "MomsDashboard", Dashboard1

Dashboard 0 and 1 are both derived from widget

Lets say you have a QListWidget where we add the strings in the list and then do the connection:

connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), 
       this, SLOT(addDashboard(QListWidgetItem*)));

void addDashboard(QListWidgetItem* item) {
    int index = listWidget->row(item);

    QWidget* widget = new typeof(command.atIndex(index).getType());
    widget->show();

}

How would I create that list and store types just like you do in C# Type?

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
chikuba
  • 4,229
  • 6
  • 43
  • 75
  • 2
    Having read your comments in Emile's answer, you need to edit your question to be explicit - are the types known at compile-time, or are they dynamically loaded through a plugin mechanism? – cmannett85 Feb 09 '12 at 07:46

1 Answers1

3

C++ does not allow you to create an object (using the new operator) where the type is only known at runtime. However, you can use a simplified form of the Factory Method pattern as a workaround.

Here's an example:

// Type IDs that are associated with a widget type
enum WidgetTypeId {
    dashboard1WidgetTypeId,
    dashboard2WidgetTypeId
};

// Factory method
QWidget* createWidget(WidgetTypeId type) {
    switch (type)
    {
        case dashboard1WidgetTypeId:
            return new DashBoard0;

        case dashboard2WidgetTypeId:
            return new DashBoard1;
    }
}

void addDashboard(QListWidgetItem* item) {
    int index = listWidget->row(item);

    QWidget* widget = createWidget(command.atIndex(index).getWidgetTypeId());
    widget->show();

}

Not very pretty, I know. If your widgets are clonable, you can use a std::map instead of the ugly switch statement. This alternative approach would be an example of the Prototype Pattern. Here's some sample code showing this approach:

class WidgetFactory
{
public:
    QWidget* create(const std::string& name) {
        return prototypes_[name]->clone();
    }

    void addPrototype(const std::string& name, QWidget* prototype) {
        prototypes_[name] = prototype;
    }

private:
    std::map<std::string, QWidget*> prototypes_;
}


WidgetFactory factory;
factory.addPrototype("DashBoard0", new DashBoard0);
factory.addPrototype("DashBoard1", new DashBoard1);


void addDashboard(QListWidgetItem* item) {
    int index = listWidget->row(item);

    QWidget* widget = factory.create(command.atIndex(index).getWidgetTypeName());
    widget->show();

}

C++ is not a very dynamic language. It has limitied RTTI capabilities and practically none of the reflection features in C#. That's why you have to resort to patterns like Factory Method and Abstract Factory.


ADDENDUM

It hasn't dawned on me that Qt might provide runtime class information beyond what is normally available in C++ (I only used Qt for simple utility apps, so I don't know all the bells & whistles available in that framework). With that in mind, I searched and found this mailing list discussion on how to instantiate Qt objects by class name. I don't know if that solution works for plugin objects, though.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
  • but how would that be different to QWidget* test2 = new typeof(EmptyWorkspace); or template QWidget* testing() { return new T(); } to this? How would I be able to solve this problem? All i want to do is to load a list where i define what class to create to which button. When a button is clicked, that widget will be created and added to QStackedWidget. The list will be created during runtime since I will be loading in packages with the classes. – chikuba Feb 09 '12 at 06:17
  • typeof is a compile time "function" that is really a compiler extension. It can only evaluate to some type at compile time. Assuming you come from C#, there is no runtime reflection available, so a lot of the things you are used are not possible. One of the main reasons is performance and space issues, and restricting compiler implementations if such a system was to be in place. I'll think about a nice way to solve this, but a brute force way would be some function with a huge switch statement, with cases for each type, where it return a new instance of that specific type. This is ugly :P – Alexander Kondratskiy Feb 09 '12 at 06:29
  • @AlexanderKondratskiy: That's the ugly thing I was writing up as an example before you put it so nicely in words. :-) – Emile Cormier Feb 09 '12 at 06:41
  • @Emile Cormier so far it seems the only direct way of dealing with the problem though, :) – Alexander Kondratskiy Feb 09 '12 at 06:46
  • There is also boost::any and the like, though. – Arafangion Feb 09 '12 at 06:55
  • @EmileCormier in your example, all the objects would be created when added in the begining right? I really like the factory example but I want to be able to have no instances running of an object until I decide to create it. The widgets might be huge and have their own modelview etc. And the case-switch example woudlnt work since I have no idea how many different plugins the user would have available. – chikuba Feb 09 '12 at 07:17
  • @chikuba: With the prototype pattern (second example), one instance *per type* will be created in the beginning, yes. With the factory method (first example), there is only one case per widget type. The switch-case is not meant to replace your command list. Could you elaborate what you mean by plugin? – Emile Cormier Feb 09 '12 at 07:28
  • it will be more kinds of dashboards that are available (different settings, data input etc) and yeas, they will all be derived from the same baseclass, but which one the user likes to attach is not availabe to the programmer. when the program loads, they will be inserted like adding classes to the program. in c# a commandlist would be filled with these. it would be the name and the kind of object that would be created if it was clicked in the menu. the user will be able to close them all down if they want to save resources. – chikuba Feb 09 '12 at 07:33
  • 1
    @chikuba: Oh, I see now that Qt has some sort of plugin mechanism. Yeah, if widget types can be defined in an external plugin loaded at runtime, that certainly complicates things. I'm afraid I can't help you with the plugin aspect, seeing that I never needed to use it. – Emile Cormier Feb 09 '12 at 07:37
  • you saved me. could not sleep last night cus you told me that plugins aren't possible in c++. made no sense. completely overlooked that fact that qt is my friend. thank you very much – chikuba Feb 09 '12 at 20:05
  • I didn't say that plugins aren't possible, just that it makes matters more complicated. Anyways, I'm sorry if I misled you. I regret attempting to answer this question in the first place. Qt is a different beast than plain old C++. – Emile Cormier Feb 09 '12 at 22:46