我使用的是c++ Builder 10.2.3
我正在尝试添加属性到不同的类(大约10)。
例如,在一个类中,我添加了:
__property UnicodeString sdkPath = {read=get_sdkPath, write=set_sdkPath};
ER_PROPERTY(UnicodeString, sdkPath, "")
__property UnicodeString algorithm = {read=get_algorithm, write=set_algorithm};
ER_PROPERTY(UnicodeString, algorithm, "")
ER_PROPERTY
定义为:
#define ER_PROPERTY(TYPE,NAME,DEFAULT);
TYPE get_##NAME() const { return NAME; }
void set_##NAME(TYPE the_##NAME) { NAME = the_##NAME; }
问题是,在执行过程中,我得到一个StackOverflow错误消息。
是否有问题使用__property
定义与这样的宏?因为宏不应该占用内存空间。他们只是被替换了?
目的是生成可以在运行时操作的RTTI属性。下面是在运行时获取RTTI的代码示例:
TRttiContext RttiCtx;
TRttiInstanceType *QInstanceType =
dynamic_cast<TRttiInstanceType*>(RttiCtx.GetType(this->ClassType()));
OR
TRttiInstanceType *QInstanceType =
dynamic_cast<TRttiInstanceType*>(RttiCtx.GetType((PTypeInfo)this->ClassInfo());
问题是,我不能使用FindType和GetTypes方法来获得Delphi RTTI类我已经定义在c++语言。那么,是否有另一种方法可以访问我添加到c++类中的属性的RTTI ?我定义的所有类主要都是从TObject派生的。
我肯定不能添加完整的代码,因为它太长了。但是我在加一些东西。希望这将有助于复制:
class QObject : public TPersistent
{
int firstAvailablePropertyIdx;
public:
void setProperty(const UnicodeString &name, Variant value);
private:
friend class Context;
}
class Context : public QObject
{
public:
ER_PROPERTY(UnicodeString, sdkPath, "");
ER_PROPERTY(UnicodeString, algorithm, "");
ER_PROPERTY(UnicodeString, log, "");
ER_PROPERTY(UnicodeString, path, "");
ER_PROPERTY(int, parallelism, std::max(1, TThread::ProcessorCount + 1));
void setProperty(const UnicodeString &key, const UnicodeString &value);
}
void QObject::setProperty(const UnicodeString &name, Variant value)
{
TRttiContext RttiCtx;
TRttiInstanceType *QInstanceType =
dynamic_cast<TRttiInstanceType*>(RttiCtx.GetType(this->ClassType()));
DynamicArray<TRttiProperty*> GlobProperty = QInstanceType->GetProperties();
}
void Context::setProperty(const UnicodeString &key, const UnicodeString &value)
{
QObject::setProperty(key, value.IsEmpty() ? Variant(true) : Variant(value));
}
Context *Globals = new Context();
Globals->setProperty("sdkPath","Test");
首先,多行宏需要在每行末尾有一个,将宏继续到下一行,例如:
#define ER_PROPERTY(TYPE,NAME,DEFAULT);
TYPE get_##NAME() const { return NAME; }
void set_##NAME(TYPE the_##NAME) { NAME = the_##NAME; }
第二,如果您实际展开ER_PROPERTY()
的每次使用,那么问题对您来说应该变得非常明显:
__property UnicodeString sdkPath = {read=get_sdkPath, write=set_sdkPath};
//ER_PROPERTY(UnicodeString, sdkPath, "")
;UnicodeString get_sdkPath() const { return sdkPath; }
void set_sdkPath(UnicodeString the_sdkPath) { sdkPath = the_sdkPath; }
__property UnicodeString algorithm = {read=get_algorithm, write=set_algorithm};
//ER_PROPERTY(UnicodeString, algorithm, "")
;UnicodeString get_algorithm() const { return algorithm; }
void set_algorithm(UnicodeString the_algorithm) { algorithm = the_algorithm; }
首先,初始的;
是错误的,需要删除。
但更重要的是,每个getter方法都是从其各自的属性中读取,属性调用getter方法,getter方法从属性中读取,属性调用getter,…以此类推,形成一个无限的递归循环。
setter方法也是如此。每个setter方法写入其各自的属性,属性调用setter方法,setter方法写入属性,属性调用setter方法,…以此类推,形成一个无限的递归循环。
这就是为什么你得到堆栈溢出错误。
你需要getter/setter方法来读/写实际的数据成员,而不是属性。
我建议用另一种方法:
#define ER_PROPERTY(TYPE,NAME,DEFAULT)
private: TYPE m_##NAME;
__published: __property TYPE NAME = { read=m_##NAME, write=m_##NAME, default=DEFAULT }
class SomeClass
{
...
ER_PROPERTY(UnicodeString, sdkPath, "");
ER_PROPERTY(UnicodeString, algorithm, "");
...
};
将展开为:
class SomeClass
{
...
//ER_PROPERTY(UnicodeString, sdkPath, "");
private: UnicodeString m_sdkPath;
__published: __property UnicodeString sdkPath = { read=m_sdkPath, write=m_sdkPath, default="" };
//ER_PROPERTY(UnicodeString, algorithm, "");
private: UnicodeString m_algorithm;
__published: __property UnicodeString algorithm = { read=m_algorithm, write=m_algorithm, default="" };
...
};
或者,如果您真的不需要访问它们生成的RTTI,您可以简单地完全摆脱__property
声明,例如:
#define ER_PROPERTY(TYPE,NAME,DEFAULT)
TYPE ##NAME /* = DEFAULT */
class SomeClass
{
...
public:
ER_PROPERTY(UnicodeString, sdkPath, "");
ER_PROPERTY(UnicodeString, algorithm, "");
...
};
将展开为:
class SomeClass
{
...
public:
//ER_PROPERTY(UnicodeString, sdkPath, "");
UnicodeString sdkPath /* = "" */;
//ER_PROPERTY(UnicodeString, algorithm, "");
UnicodeString algorithm /* = "" */ ;
...
};
请注意,在类的声明中初始化类成员需要c++ 11或更高版本,这只有c++ Builder基于clang的编译器支持。