首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

对象属性的C++兑现

2012-08-14 
对象属性的C++实现  高级语言的面向对象编程模型一般都支持“属性”接口,例如 Visual Basic 和 C#。在C#中,通

对象属性的C++实现

  高级语言的面向对象编程模型一般都支持“属性”接口,例如 Visual Basic 和 C#。在C#中,通过访问属性,不仅可以存取数据,还可以在存取时执行其它操作,在代码形式上,改变属性值可以写成给变量赋值的形式,例如:Form1.Size = System.Drawing.Size(640,480),而不是调用函数:Form1.SetSize ...(实际上Form没有SetSize函数)。C++语言不支持对象属性,对象的可执行接口只有函数,所以C++里没有“属性”和“方法”的概念。但是通过一些编程的技巧,可以实现一个属性访问器,使 C++ 代码可以具有和 C# 相似的编程风格。

属性访问器模板

  代码如下:

template<typename TObject, typename TProperty>

struct PropAccessor{    TObject* Instance;    PropAccessor(TObject* instance): Instance(instance){}    operator TProperty();    TProperty& operator = (TProperty value);};

  其中:operator TProperty() 用来实现属性的"get"部分,TProperty& operator=(TProperty value) 用来实现属性的"set"部分。

  这个模板是不能直接使用的,两个运算符函数都没有实现,为了可以使用,需要继承模板并实现这两个运算符。这样就定义了一个模拟的“属性”。

属性访问器的实现

  下面是一个具体的实现例子。MeshNode是用于3D场景的模型对象,float3是一个向量类型,表示Mesh在场景中的位置,float4x4是一个矩阵类型,表示Mesh的变换矩阵。演示的代码是MeshNode中的Position属性。

union float3 //一个简单的向量类型。{    float m[3];    struct    {        float x, y, z;    };    float3()    {        for(int i = 0; i < 3; i++)        {            this->m[i] = 0.0f;        }    };};union float4x4 //一个简单的矩阵类型。{    float m[16];    struct    {        float _11, _12, _13, _14;        float _21, _22, _23, _24;        float _31, _32, _33, _34;        float _41, _42, _43, _44;    };    float4x4()    {        for(int i = 0; i < 16; i++)        {            this->m[i] = 0.0f;        }    };}; class MeshNode{public:    //属性访问器的实现类。这个类直接嵌套在MeshNode,用来实现属性"Position".    class PROP_Position: public PropAccessor<MeshNode, float3>    {        friend class MeshNode;//这个声明使MeshNode可以创建PROP_Position对象,而外部调用者不能创建PROP_Position,因为下面的构造函数是私有。    private:        PROP_Position(MeshNode* instance): PropAccessor(instance){};    public:        //Property "get":实现了模版中对应的运算符,TProperty被替换为float3。这里只是简单的取得数据,也可以做任何其它操作。        operator float3()        {            float3 rv;            rv.x = this->Instance->m_WorldMatrix._41;            rv.y = this->Instance->m_WorldMatrix._42;            rv.z = this->Instance->m_WorldMatrix._43;            return rv;        };        //Property "set":实现了模板中对应的运算符,TProperty被替换为float3。这里只是简单的保存数据,也可以做任何其它操作。        float3& operator=(const float3& value)        {            this->Instance->m_WorldMatrix._41 = value.x;            this->Instance->m_WorldMatrix._42 = value.y;            this->Instance->m_WorldMatrix._43 = value.z;            return value;        };    };//private:    //    //...    float4x4 m_WorldMatrix;    //public:    //    //...    //    //属性"Position":取得/设置对象的位置。(前面"PROP_Position"的一堆代码就为了实现这个).    PROP_Position Position()    {        return PROP_Position(this);    };};

属性访问器的使用

  有了这些代码,就可以使用"Position"属性了,MeshNode中的Position函数返回的是一个PROP_Position对象,通过这个对象的运算符使代码具有使用属性的风格。例如:

MeshNode* my_mesh = new MeshNode();float3 my_pos;my_pos.x = 10.0f;my_pos.y = 10.0f;my_pos.z = 10.0f;my_mesh->Position() = my_pos; //有了使用属性的代码形式。这时调用了"MeshNode::PROP_Position::operator=()"函数。float3 world_pos = my_mesh->Position(); //和普通C++函数形式相同,但是用到了属性访问器,这时调用了"MeshNode::PROP_Position::operator float3()"函数。

简单总结

  这个属性访问器的优点就不用多说了,主要讨论缺点。具体开发中,可以根据具体情况来决定是否使用它。

  1. 增加了代码量。需要编写多余的代码,为每个属性接口实现一个访问器。

  2. 和传统的"getPosition"和"setPosition"函数相比,通过属性访问器对数据访问,效率略有下降。在"get"过程中,额外的操作是:创建并返回一个访问器对象,调用运算符"operator TProperty()";在"set"过程中,额外的操作是:创建并返回一个访问器对象,调用运算符"TProperty& operator = (TProperty)",且属性值多了一次引用传递。

  3.不能被重载。这样实现的属性不能被重载,如果需要重载,需要更复杂的实现方法。如果不想折腾的话,在程序的设计中就要尽量避免重载属性。

  总体来说对性能影响不大,在不苛刻要求效率的情况下,这些额外的开销可以忽略。只是增加了实现属性访问器的开发工作,如果希望属性可以被重载,需要更多的技巧和工作量,实现方法其实也没有难度,大家可以自由发挥。

热点排行