gpt4 book ai didi

c++ - C++ 设计中的属性处理

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:31:58 27 4
gpt4 key购买 nike

这就是困扰我的地方:我有一个类的层次结构,其中包含一组属性,这些属性要么是必需的,要么不是。这些类被序列化为 XML(或其他格式)。必须的属性应该一直序列化,那些不是的,只有在我指定它们时才应该序列化。

我正在寻找一种尽可能自动化此过程的方法,而不必专门检查每个属性是否已设置值。

这是一个例子:

 class Book
{

QString m_author; // this is optional
QString m_secondaryAuthor; // this is optional
QString m_title; // this is mandatory

public:
QString serializePlainText()
{
QString result = "Book:";
result += m_title;
if(m_author.length()) result+= " by "+m_author;
if(m_SecondaryAuthor.length()) result+= " and "+m_SecondaryAuthor;
return result;
}

void setTitle(const QString& title)
{
m_title = title;
}

void setAuthor(const QString& author)
{
m_author = author;
}
};

当然,这只是一个简单的例子,现实生活中要复杂得多,一个类可以有上百个属性。问题的第二部分出现了:我需要能够以更严格的方式设置属性,即。不使用我将值映射到字符串属性的映射,但或多或​​少类似于上面的示例(使用设置函数 setTitle(const QString&) ...等....

考虑到这样做的任何奇特的方式:

  1. 无需手动声明和检查所有属性
  2. 拥有漂亮且对程序员友好的 API?

我或多或少地坚持使用 Qt,但这不是强制性的。

谢谢,f.

最佳答案

如果你愿意使用预处理器为你生成代码,可以依赖Boost.Preprocessor .例如,您可以按照以下方式做一些事情:

#define GET_TYPE( pair ) BOOST_PP_TUPLE_ELEM( 2, 0, pair )
#define GET_NAME( pair ) BOOST_PP_TUPLE_ELEM( 2, 1, pair )

#define DECLARE_MANDATORY( r, data, elem ) GET_TYPE( elem ) GET_NAME( elem );

#define DECLARE_MANDATORY_ATTRIBUTES( attributes ) \
BOOST_PP_SEQ_FOR_EACH( DECLARE_MANDATORY, ~, attributes )

#define DECLARE_OPTIONAL( r, data, elem ) boost::optional< GET_TYPE( elem ) > GET_NAME( elem );

#define DECLARE_OPTIONAL_ATTRIBUTES( attributes ) \
BOOST_PP_SEQ_FOR_EACH( DECLARE_OPTIONAL, ~, attributes )

#define MANDATORY_ACCESSORS( r, data, elem ) \
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ) = value; } \
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return GET_NAME( elem ); }

#define DEFINE_MANDATORY_ACCESSORS( attributes ) \
BOOST_PP_SEQ_FOR_EACH( MANDATORY_ACCESSORS, ~, attributes )

#define OPTIONAL_ACCESSORS( r, data, elem ) \
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ).reset(value); } \
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return *GET_NAME( elem ); }

#define DEFINE_OPTIONAL_ACCESSORS( attributes ) \
BOOST_PP_SEQ_FOR_EACH( OPTIONAL_ACCESSORS, ~, attributes )

class Book
{
#define BOOK_MANDATORY_ATTRIBUTES ((std::string, title))
#define BOOK_OPTIONAL_ATTRIBUTES ((std::string, author)) ((std::string, secondaryAuthor))

public:

DECLARE_MANDATORY_ATTRIBUTES( BOOK_MANDATORY_ATTRIBUTES )
DECLARE_OPTIONAL_ATTRIBUTES( BOOK_OPTIONAL_ATTRIBUTES )

DEFINE_MANDATORY_ACCESSORS( BOOK_MANDATORY_ATTRIBUTES )
DEFINE_OPTIONAL_ACCESSORS( BOOK_OPTIONAL_ATTRIBUTES )
};

int main()
{
Book b;
b.set_title("H2G2");

std::cout << b.get_title();

b.set_author("Douglas Adams");
std::cout << b.get_author();
}

您可以创建另一个宏来为您的序列化函数生成代码,利用 [boost::optional](http://www.boost.org/libs/optional] 来测试是否设置了可选属性。

如果您不想进行代码生成,您将无法自动获取属性的访问器。然而,序列化方面可以更经典地处理,例如通过为所有属性使用公共(public)基类。这样,您可以将它们存储在一个容器中,并迭代它们以要求它们序列化自己:

struct Attribute
{
virtual QString serializePlainText() = 0;
};

// Generic attribute for the most common cases
template <typename T>
class MandatoryAttribute : public Attribute
{
T value;

public:

std::string serializePlainText()
{
return boost::lexical_cast<std::string>(value);
}
};

// Generic attribute for the most common cases
template <typename T>
class OptionalAttribute : public Attribute
{
boost::optional<T> value;

public:

bool isSet() const { return value; }

std::string serializePlainText()
{
return isSet() ?
boost::lexical_cast<std::string>(value) :
"";
}
};

关于c++ - C++ 设计中的属性处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11016176/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com