Qt&C ++:具有不同返回值和参数类型的函数指针数组

时间:2019-04-12 21:47:40

标签: c++ qt callback

我正在研究C ++ 11,Qt 5.12。我需要将函数指针存储在某些映射或数组中。关键是,这些方法具有不同的返回类型和参数类型。

我在类中定义了一些简单的数据结构。这是一个尽可能简单的示例:

class TableData
{
public:
    enum EnumFieldType
    {
        FieldType_None = 0,
        FieldType_Int,
        FieldType_QString
    };
    enum EnumFieldId
    {
        FieldId_None = 0,
        FieldId_Id,
        MaxSystemFieldId = 64
    };
int id() const;
void setId(const int _id);
QVariant getFieldValue(int _fieldId);
void setFieldValue(int _fieldId, QVariant _value)
protected:
int id_;
//Here some QMap or QVector with the function pointers
}

class EmployeeData : public TableData
{
public: 
    enum EnumFieldId
    {
        FieldId_Name = TableData::MaxSystemFieldId + 1,
        FieldId_Age
    };
   QString name() const;
   int age() const;
   void setName(const QString &_name);    
   int setAge(const Int &_age);    
protected:
    int             age_;
    QString         name_;
}

想法是在TableData中创建三个映射:

  • QMap mapFieldTypes
  • QMap mapGetters
  • QMap

这些映射将填充到TableData子类的构造函数中。因此,一旦建立了子类的实例,我就可以使用:

EmployeeData  ed;
ed.setId(5);
ed.setAge(11);
ed.setName("Son Gohan");

或者:

EmployeeData ed;
ed.setField(EmployeeData::FieldId_Id, 5);
ed.setField(EmployeeData::FieldId_Age, 11);
ed.setField(EmployeeData::FieldId_Name, "Son Gohan");

这些最后的调用转到TableData :: SetField方法,该方法应使用FieldId键查看地图mapFieldTypes以获取字段的类型;然后获取setter函数的指针,并使用QVariant参数将其正确转换为setter函数所请求的类型。

我花了很多时间为此苦苦挣扎,阅读,寻找和寻找解决方案。指针或回调数组必须具有相同的函数类型,std :: function和std :: bind不能解决此问题(数组必须具有相同的函数类型,并且bind已使用预定义的值,等等)...我需要类似的东西指向应用于变量的(void *)指针,但对于函数指针(使用类型映射,我认为我可以将通用函数指针有效地转换为所需的函数指针模板)。

有什么想法吗?

PD:对某些代码问题或错别字,很抱歉,实际代码要复杂得多,我已尝试尽可能简化和简化它。

1 个答案:

答案 0 :(得分:2)

Qt's Property System似乎是您的理想解决方案:

class TableData : public QObject {
    Q_OBJECT

    public:
        TableData() : QObject(), _id(0) {}

        QVariant getFieldValue(const char * fieldName) const {
            return property(fieldName);
        }

        void setFieldValue(const char * fieldName, QVariant _value) {
            setProperty(fieldName, _value);
        }

        int id() const { return _id; }

        void setId(int newID) {
            _id = newID;
            emit idChanged();
        }

    protected:
        Q_PROPERTY(int id
                   READ id
                   WRITE setId
                   NOTIFY idChanged)
        int _id;

    signals:
        void idChanged();
};
class EmployeeData : public TableData {
    Q_OBJECT

    public:
        EmployeeData() : TableData(), _age(-1), _name("") {}

        int age() const { return _age; }

        void setAge(int newAge) {
            _age = newAge;
            emit ageChanged();
        }

        QString name() const { return _name; }

        void setName(QString newName) {
            _name = newName;
            emit nameChanged();
        }

    protected:
        Q_PROPERTY(int age
                   READ age
                   WRITE setAge
                   NOTIFY ageChanged)
        int _age;

        Q_PROPERTY(QString name
                   READ name
                   WRITE setName
                   NOTIFY nameChanged)
        QString _name;

    signals:
        void ageChanged();
        void nameChanged();
};

void TableData::setField(const char *, QVariant);方法将调用void QObject::setProperty(const char *, QVariant);。最后一个将自动调用您在WRITE属性字段中指定的设置器,以更新属性值。以下三段代码完全可以完成相同的操作:

使用属性的设置器:

EmployeeData ed;
ed.setId(5);
ed.setAge(11);
ed.setName("Son Gohan");

使用void TableData::setField(const char *, QVariant);

EmployeeData ed;
ed.setField("id", 5);
ed.setField("age", 11);
ed.setField("name", "Son Gohan");

使用void QObject::setProperty(const char *, QVariant);(因为您的EmployeeData也是QObject

EmployeeData  ed;
ed.setProperty("id", 5);
ed.setProperty("age", 11);
ed.setProperty("name", "Son Gohan");

读取属性的方法相同。您的QVariant TableData::getField(const char *) const;方法将调用QVariant QObject::property(const char *) const;。最后一个将自动调用您在READ属性字段中指定的getter,以检索属性值。以下三段代码完全可以完成相同的操作:

使用属性的设置器:

// Using the EmployeeData ed defined above
int id = ed.id();            // id == 5
int age = ed.age();          // age == 11
QString name = ed.name();    // name == "Son Gohan"

使用QVariant TableData::getField(const char *) const;

// Using the EmployeeData ed defined above
int id = ed.getField("id").toInt();               // id == 5
int age = ed.getField("age").toInt();             // age == 11
QString name = ed.getField("name").toString();    // name == "Son Gohan"

使用QVariant QObject::property(const char *) const;(因为您的EmployeeData也是QObject

// Using the EmployeeData ed defined above
int id = ed.property("id").toInt();               // id == 5
int age = ed.property("age").toInt();             // age == 11
QString name = ed.property("name").toString();    // name == "Son Gohan"