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

Posted

技术标签:

【中文标题】是否可以在不使用成员函数的情况下实现 Q_PROPERTY READ/WRITE 访问器?【英文标题】:Is it possible to implement Q_PROPERTY READ/WRITE accessors without using member functions? 【发布时间】:2015-08-23 16:23:36 【问题描述】:

一般来说,很多代码除了获取/设置类成员之外什么都不做。为此,我实现了一个简单的容器类来关联 getter 和 setter 到一个“领域”。乍一看,这看起来还不错,而且代码少得多。这是容器类的样子:

会员.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()  
;

我知道有些事情还不完美,但现在没关系。接下来的几行展示了如何定义Member 实例以及访问底层数据的简单方便的方法。 getsetnotify 函数可以替换为 lambda 或函数指针以覆盖自定义行为。

ma​​in.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;

现在的问题是 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); 
;

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

编辑

如下所述,MEMBER 关键字可以在不指定 get 和 set 函数的情况下拥有属性。但是,私有成员只能通过其名称 (this-&gt;property("myPropertyName")) 访问,而且除了“普通”获取和设置之外,没有其他方法可以实现。

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

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

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

感谢您的帮助!

【问题讨论】:

也许你应该尝试一些宏的魔法?将 Q_PROPERTY 宏包装到另一个将创建 2 个方法 + 声明属性的宏。我不确定,但它可能与 MOC 编译器不兼容。 另一种方式——在运行时创建动态属性。 @SaZ 我会尽量避免使用宏。但是动态属性可能是一种选择,我会尝试一下。感谢您的提示! 【参考方案1】:

我认为在不编写包装器的情况下将READWRITE 属性方法重定向到其他内部或外部对象是不可能的,但是如果您的getter 和setter 除了返回或设置数据之外不做任何事情:那里至少在最新的 Qt 版本中是 MEMBER 变量关联。

来自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])

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

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

如果没有 READ 访问器函数,则需要一个 MEMBER 变量关联 被指定。这使给定的成员变量可读并且 无需创建 READ 和 WRITE 访问器即可写入 功能。仍然可以使用 READ 或 WRITE 访问器函数 除了 MEMBER 变量关联(但不是两者),如果你需要 控制变量访问。

使用MEMBER,您无需编写getter 和setter。

【讨论】:

以上是关于是否可以在不使用成员函数的情况下实现 Q_PROPERTY READ/WRITE 访问器?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中,如何在不使用 if 语句的情况下选择运行特定的成员函数?

一个类能否在内部监控其成员函数的使用和参数

如何在不向下转换的情况下调用派生类的成员函数

在不事先了解特定成员函数的情况下从另一个类访问成员函数

可以在不调用 memset 的情况下从构造函数初始化器列表中将成员结构设为零吗?

是否可以在不使用malloc的情况下进行内存泄漏?