是否可以在不使用成员函数的情况下实现 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
实例以及访问底层数据的简单方便的方法。 get
、set
和 notify
函数可以替换为 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;
现在的问题是 Q_PROPERTY
宏需要 READ
和 WRITE
访问器的函数名称,而我又回到了开始的地方:我必须为每个属性显式编写 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.get
和m_flag.set
函数?我尝试了显而易见的事情,但它们要么被 moc 拒绝,要么导致代码过多。
编辑
如下所述,MEMBER
关键字可以在不指定 get 和 set 函数的情况下拥有属性。但是,私有成员只能通过其名称 (this->property("myPropertyName")
) 访问,而且除了“普通”获取和设置之外,没有其他方法可以实现。
为了更清楚:动机不仅仅是避免编写 get 和 set 函数,而是尝试实现一个灵活的成员系统,
默认情况下按预期执行获取/设置 支持自定义逻辑(例如将新设置的值转发到其他实例) 可用于 C++ 类成员并与 Qt 属性兼容唯一缺少的部分是Q_PROPERTY
READ
/WRITE
accessors 和Member
类的get/set 方法之间的桥梁。
感谢您的帮助!
【问题讨论】:
也许你应该尝试一些宏的魔法?将Q_PROPERTY
宏包装到另一个将创建 2 个方法 + 声明属性的宏。我不确定,但它可能与 MOC 编译器不兼容。
另一种方式——在运行时创建动态属性。
@SaZ 我会尽量避免使用宏。但是动态属性可能是一种选择,我会尝试一下。感谢您的提示!
【参考方案1】:
我认为在不编写包装器的情况下将READ
或WRITE
属性方法重定向到其他内部或外部对象是不可能的,但是如果您的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 语句的情况下选择运行特定的成员函数?