Qt & C ++: Массив указателей на функции с различными типами возвращаемых значений и параметров - PullRequest
0 голосов
/ 13 апреля 2019

Я работаю на 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, который должен посмотреть наmap mapFieldTypes с ключом FieldId, чтобы получить тип поля;затем получите указатель на функцию-установщик и вызовите его с параметром QVariant, правильно преобразованным в тип, запрошенный функцией-установщиком.

Я потратил много часов, пытаясь найти решение, находя и ища какое-то решение.,Массивы указателей или обратных вызовов должны быть одного типа функции, std :: function и std :: bind не решают эту проблему (массивы должны быть одного типа функции, а bind использует уже предопределенные значения и т. Д.) ... Мне нужно нечто подобноеуказатель (void *), применяемый к переменным, но для указателей на функции (используя карту типов, я думаю, что я могу эффективно преобразовать указатель универсальной функции на нужный шаблон указателя на функцию).

Есть идеи?

PD: Извините за некоторые проблемы с кодом или опечатки, реальный код гораздо более проработан, и я попытался максимально упростить и упростить его.

1 Ответ

2 голосов
/ 13 апреля 2019

Похоже, Система свойств Qt - идеальное решение для вас:

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, чтобы получить значение свойства. Следующие три фрагмента кода точно так же делают:

Использование установщиков атрибутов:

// 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...