是否可以在不使用成员函数的情况下实现Q_PROPERTY READ/WRITE访问器?

qCr*_*ing 6 qt qml c++11

通常,很多代码除了获取/设置类成员之外什么都不做.为此,我实现了一个简单的容器类,使getter和setter与"field"相关联.乍一看,这看起来很不错,导致代码少得多.这是容器类的样子:

Member.h

#include <functional>

template <class T>
class Member
{
public:
  T data;

  using Getter_t = std::function<T(void)>;
  using Setter_t = std::function<void(T)>;
  using Notify_t = std::function<void(void)>;

  Setter_t m_setterFunc;
  Getter_t m_getterFunc;
  Notify_t m_notifyFunc;

  Member()
  {
      this->m_getterFunc  = [=] (void) -> T  { return this->data; };
      this->m_setterFunc  = [=] (T data) -> void { this->data = data; };
      this->m_notifyFunc  = [] (void) -> void { };
  }

  auto get() -> T { return this->m_getterFunc(); }
  auto set(T data) -> void { this->m_setterFunc(data); this->m_notifyFunc(); }

  auto getter(Getter_t func) -> Member& { this->m_getterFunc  = func; return *this; }
  auto setter(Setter_t func) -> Member& { this->m_setterFunc  = func; return *this; }
  auto notify(Notify_t func) -> Member& { this->m_notifyFunc  = func; return *this; }

  ~Member() { }
};
Run Code Online (Sandbox Code Playgroud)

我知道有些事情还不完美,但现在还可以.接下来的几行显示了如何Member定义实例以及访问底层数据的简单方便的方法.get,setnotify功能可通过lambda表达式或函数指针来代替重写自定义行为.

main.cpp中

#include <iostream>

#include "Member.h"

class MyClass
{
public:
    Member<int> foo;
    Member<std::string> bar;

    void barChanged() { std::cout << "bar changed\n"; }
};

auto main(int argc, const char * argv[]) -> int
{
    MyClass instance;

    instance.foo.notify([] () -> void { std::cout << "foo changed\n"; });
    instance.bar.notify(std::bind(&MyClass::barChanged, instance));

    instance.foo.set(10);
    instance.bar.set("some string");

    std::cout << instance.foo.get() << " " << instance.bar.get() << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是Q_PROPERTY宏需要READWRITE访问器的函数名称,我回到我开始的地方:我必须明确地为每个属性编写get和set函数.正是我想要避免的.

class MyOtherClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool flag READ getFlag WRITE setFlag NOTIFY flagChanged);
public:
    Member<bool> m_flag;
    auto getFlag() -> bool { return m_flag.get(); }
    auto setFlag(bool flag) -> void { this->m_flag.set(flag); }
};
Run Code Online (Sandbox Code Playgroud)

是否有可能直接使用已有的m_flag.getm_flag.set功能?我尝试了一些显而易见的事情,但是他们要么被moc拒绝,要么导致代码过多.

编辑

如下所述,MEMBER关键字使得可以在不指定get和set函数的情况下获得属性.但是,私有成员只能通过他们的名字(this->property("myPropertyName"))来访问,而且没有办法实现"普通"获取和设置.

为了更清楚:动机不仅仅是避免编写get和set函数,而是试图实现一个灵活的成员系统

  • 默认情况下按预期执行get/set
  • 支持自定义逻辑(例如将新设置的值转发给其他实例)
  • 可用于C++类成员,并与Qt属性兼容

唯一缺少的部分是Q_PROPERTY READ/ WRITEaccessors和类的get/set方法之间的桥梁Member.

谢谢你的帮助!

Elo*_*eth 7

我不认为可以在没有编写包装器的情况下将方法重定向READWRITE属性转换为其他内部或外部对象,但如果你的getter和setter除了返回或设置数据之外什么都不做的话:MEMBER至少在最新的Qt版本中存在变量关联.

来自Qt Doc:

Q_PROPERTY(type name
           (READ getFunction [WRITE setFunction] |
            MEMBER memberName [(READ getFunction | WRITE setFunction)])
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [REVISION int]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL])
Run Code Online (Sandbox Code Playgroud)

如果未指定MEMBER变量,则需要READ访问器功能.这是为了阅读房产价值.理想情况下,const函数用于此目的,它必须返回属性的类型或对该类型的const引用.例如,QWidget :: focus是一个具有READ函数的只读属性,QWidget :: hasFocus().

WRITE访问器功能是可选的.它用于设置属性值.它必须返回void并且必须只接受一个参数,可以是属性的类型,也可以是指向该类型的指针或引用.例如,QWidget :: enabled具有WRITE函数QWidget :: setEnabled().只读属性不需要WRITE函数.例如,QWidget :: focus没有WRITE功能.

如果未指定READ访问器函数,则需要MEMBER变量关联.这使得给定成员变量可读写,而无需创建READ和WRITE访问器函数.如果需要控制变量访问,除了MEMBER变量关联(但不是两者)之外,仍然可以使用READ或WRITE访问器函数.

使用MEMBER你不需要编写getter和setter.