组件:c语言版本属性集PropertySet

本文介绍了如何使用C++和C语言设计一个简单的属性系统,该系统允许通过字符串来设置和获取对象的属性值,支持基础数据类型的转换。核心思想是使用属性表存储属性,并绑定处理函数,实现类型转换。示例代码展示了如何定义和使用这样的属性集,以及相关的数据结构和转换函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景介绍

我想使用过QT的同学会比较熟悉里面的一个概念"属性"Property。用过CEGUI的人也会发现里面有一个小型的“属性集”PropertySet。它们通常被集成在基础组件中,被用来做对象的属性设置接口,这套系统为配置文件和界面布局工具带来了便利

int value = 0;
myType t;
t.setValue("A", "123");
t.getValue("A", &value);

以上就是较为常用的方式,通过字符串的设置,来将属性数值直接传递给对象。而屏蔽掉具体的类型。由于编辑器生成的配置文件是字符串序列,这样设计会方便整合。

我之前参考QT和CEGUI使用c++做过一个,但是模板套模板,看起来比较复杂。

后来使用c设计一个类似的组件,核心就两对文件,很好理解

基本思路就是用一张表存储属性,属性可以绑定处理函数。通过转化类型来达成目的。尽量简洁设计,直接支持基础数据类型的转换,可以拓展数据类型。我们需要string和map来辅助实现。

1.最终使用案例

https://bitbucket.org/mm_longcheng/mm-core/src/dev/mm/src/core/mmPropertySet.h

struct myType
{
    struct mmPropertySet s;
    int a;
};
void myType_Init(struct myType* p);
void myType_Destroy(struct myType* p);
void myType_SetValueA(struct myType* p, const int* value);
void myType_GetValueA(const struct myType* p, int* value);

void myType_Init(struct myType* p)
{
    mmPropertySet_Init(&p->s);
    p->a = 0;
    
    static const char cOrigin[] = "myType";
    // bind object for this.
    mmPropertySet_SetObject(&p->s, p);
    // bind member property.
    mmPropertyDefine(&p->s,
        "A", struct myType,
        a, UInt, "0",
        &myType_SetValueA,
        &myType_GetValueA,
        cOrigin,
        "a value");
}
void myType_Destroy(struct myType* p)
{
    p->a = 0;
    mmPropertySet_Destroy(&p->s);
}

void myType_SetValueA(struct myType* p, const int* value)
{
    p->a = (*value);
}
void myType_GetValueA(const struct myType* p, int* value)
{
    (*value) = p->a;
}

static void PropertySetFunc(void)
{
    int value = 0;
    // weak string not need Allocator.
    struct mmString v;
    struct myType t;
    mmString_MakeWeak(&v, "123");
    myType_Init(&t);
    printf("a: %d\n", t.a);
    // a: 0
    mmPropertySet_SetValueString(&t.s, "A", &v);
    mmPropertySet_GetValueMember(&t.s, "A", &value);
    // a: 123 value: 123
    printf("a: %d value: %d\n", t.a, value);
    myType_Destroy(&t);
}

2.前置数据结构组件

#include "core/mmString.h"
#include "container/mmRbtreeString.h"

#include "core/mmValueTransform.h"

// mmString 是一个字符串组件.
// 参考这篇文章 https://joellaity.com/2020/01/31/string.html
//
// mmRbtreeString 需要一个<字符串, void*>表
// 参考 http://en.wikipedia.org/wiki/Rbtree
// 以及linux rbtree.
// 
// mmValueTransform 是一组字符串和基础类型互转的函数集合.

3.主要数据结构

struct mmProperty;

// 字符串与类型之间的转换协议
struct mmPropertyHelper
{
    void(*SetValueString)(const struct mmProperty* p, 
        void* obj, const struct mmString* pValue);

    void(*GetValueString)(const struct mmProperty* p, 
        const void* obj, struct mmString* pValue);
};

// 属性的定义
struct mmProperty
{
    struct mmString hName;
    struct mmString hHelp;
    struct mmString hDefault;
    struct mmString hOrigin;
    size_t hMemberOffset;
    size_t hMemberLength;
    void* pSetterFunc;
    void* pGetterFunc;
    struct mmPropertyHelper hHelper;
};

// 属性集合,记录了<名字, 属性>的一张表
struct mmPropertySet
{
    struct mmRbtreeStringVpt rbtree;
    void* obj;
};

4.主要处理函数,取其中一种。

void mmPropertyHelper_SetValueStringUInt(const struct mmProperty* p, void* obj, const struct mmString* pValue)
{
    typedef void(*SetterFuncType)(void* obj, const void* value);
    SetterFuncType hFunc = (SetterFuncType)(p->pSetterFunc);
    mmUInt_t hArgs = 0;
    const char* pString = mmString_CStr(pValue);
    mmValue_AToUInt(pString, &hArgs);
    assert(hFunc && "hFunc is invalid.");
    (*(hFunc))(obj, &hArgs);
}
void mmPropertyHelper_GetValueStringUInt(const struct mmProperty* p, const void* obj, struct mmString* pValue)
{
    typedef void(*GetterFuncType)(const void* obj, void* value);
    GetterFuncType hFunc = (GetterFuncType)(p->pGetterFunc);
    mmUInt_t hArgs = 0;
    char pString[16] = { 0 };
    assert(hFunc && "hFunc is invalid.");
    (*(hFunc))(obj, &hArgs);
    mmValue_UIntToA(hArgs, pString);
    mmString_Appends(pValue, pString);
}
MM_EXPORT_DLL const struct mmPropertyHelper mmPropertyHelperUInt =
{
    &mmPropertyHelper_SetValueStringUInt,
    &mmPropertyHelper_GetValueStringUInt,
};

5.原理

// 定义一个void*的成员用于存储绑定的函数
void* pSetterFunc;

// 实际需要被绑定的函数,注意参数是以常用函数的形式定义的
void myType_SetValueA(struct myType* p, const int* value);

// 函数的绑定
pSetterFunc = &myType_SetValueA;

// 函数的使用,注意我们定义了一个(void*, const void*)的泛型函数
typedef void(*SetterFuncType)(void* obj, const void* value);
SetterFuncType hFunc = (SetterFuncType)(p->pSetterFunc);
// 在cpu将参数压入栈中时,数据位宽合规,是安全的,最终正常触发绑定函数,达到泛型
(*(hFunc))(obj, pValue);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值