带有宏的c++ Builder __属性定义



我使用的是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的编译器支持。

最新更新