以前用DELPHI和C#时,对DELPHI和C#语法中的属性感到十分方便,在读写属性时能自动调用属性的get, set函数或代码.但我最喜欢的C++中没有属性机制.不过C++提供了范型编程和操作符重载机制,足以让一切变成可能.
假定要添加属性的类是目标类,给C++添加属性机制,我的想法是建立一个类,重载此类的 "=" 操作符,这样给这个类赋值时,会调用此类的operator = 函数,在此函数中调用目标类的类成员函数即可.但要调用目标类的类成员函数,需要目标类类指针和类成员函数指针.类成员函数指针的类型可以通过模板传入.废话不多说,代码如下:(VC7中编译通过,GCC还未测试)
Property.h
/*
by 剑神一笑
属性定义单元
*/
#ifndef PROPERTY_H
#define PROPERTY_H
//辅助类,用来定义类成员函数指针类型
template<typename T, typename U>
class PropertyType
{
public:
//指向类成员函数的指针类型
typedef void (U::*SetProc)(const T&);
typedef const T& (U::*GetProc)();
};
//属性基类
template<typename U>
class PropertyBase
{
protected:
//拥有这个属性的类的指针
U* obj_;
public:
void SetObj(U *obj)
{
this->obj_ = obj;
}
};
//只写属性过程定义
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set>
class WriteProperty: public PropertyBase<U>
{
protected:
//定义属性set的函数指针
typename PropertyType<T, U>::SetProc SetValue;
public:
WriteProperty()
{
this->SetValue = Set;
}
void operator= (const T &value) const
{
(obj_->*SetValue)(value);
}
};
//只读属性过程定义
template<typename T, typename U, typename PropertyType<T, U>::GetProc Get>
class ReadProperty: public PropertyBase<U>
{
private:
//避免让只读属性可写
void operator= (const T&) {}
void operator= (const ReadProperty<T, U, Get>&) {}
protected:
//定义属性get的函数指针
typename PropertyType<T, U>::GetProc GetValue;
public:
ReadProperty()
{
this->GetValue = Get;
}
operator T() const
{
return (obj_->*GetValue)();
}
};
template<typename T, typename U, typename PropertyType<T, U>::GetProc Get>
std::ostream& operator << (std::ostream &out, const ReadProperty<T, U, Get>& rv)
{
out << rv.operator T();
return out;
}
//读写属性过程定义
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set, typename PropertyType<T, U>::GetProc Get>
class ReadWriteProperty: public PropertyBase<U>
{
private:
typename PropertyType<T, U>::SetProc SetValue;
typename PropertyType<T, U>::GetProc GetValue;
//禁用赋值和拷贝构造
const ReadWriteProperty<T, U, Set, Get>& operator= (const ReadWriteProperty<T, U, Set, Get>&) {}
ReadWriteProperty(ReadWriteProperty<T, U, Set, Get>&) {}
public:
ReadWriteProperty()
{
SetValue = Set;
GetValue = Get;
}
const ReadWriteProperty<T, U, Set, Get>& operator= (const T &value) const
{
(obj_->*SetValue)(value);
return *this;
}
operator T() const
{
return (obj_->*GetValue)();
}
};
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set, typename PropertyType<T, U>::GetProc Get>
std::ostream& operator << (std::ostream &out, const ReadWriteProperty<T, U, Set, Get>& rv)
{
out << rv.operator T();
return out;
}
//简化函性定义的宏
//定义读写属性
#define PROPERTY_DECLARE_RW(property_name, type, class_type, set, get) /
ReadWriteProperty<type, class_type, class_type::set, class_type::get> property_name;
//定义只读属性
#define PROPERTY_DECLARE_R(property_name, type, class_type, get) /
ReadProperty<type, class_type, class_type::get> property_name;
//定义只写属性
#define PROPERTY_DECLARE_W(property_name, type, class_type, set) /
WriteProperty<type, class_type, class_type::set> property_name;
#define INIT_PROPERTY(property_name) property_name.SetObj(this);
#endif//PROPERTY_H
//-------------------------华丽的分隔线-----------------------------
测试代码
#include <iostream>
#include <string>
#include "Property.h"
using std::cin;
using std::cout;
using std::string;
class Test
{
private:
int value_;
string name_;
public:
Test(int value)
{
INIT_PROPERTY(Value);
INIT_PROPERTY(Name);
INIT_PROPERTY(WValue);
this->value_ = value;
name_ = "TestClass";
}
void SetValue(const int& value)
{
cout << "Set Value: " << value << std::endl;
this->value_ = value;
}
const int& GetValue()
{
cout << "Get Value: " << value_ << std::endl;
return value_;
}
const string& GetName()
{
return name_;
}
void ShowValue()
{
cout << "Value: " << value_ << std::endl;
}
//声明可读写属性,参数为: 属性名,属性类型,当前类名,Set函数,Get函数
PROPERTY_DECLARE_RW(Value, int, Test, SetValue, GetValue);
PROPERTY_DECLARE_R(Name, string, Test, GetName);
PROPERTY_DECLARE_W(WValue, int , Test, SetValue);
};
int main()
{
Test t(100);
t.ShowValue();
t.WValue = 999; //只写属性可以写入
//int i = t.WValue; //只读属性无法读取
t.Value = 200; //读写属性可以写入
int i = t.Value; //读写属性可以读取
cout << "i: " << i << std::endl;
cout << t.Name << std::endl; //只读属性可以读取
//t.Name = "hello"; //只写属性无法写入
cin.get();
return 0;
}
运行结果:
Value: 100
Set Value: 999
Set Value: 200
Get Value: 200
i: 200
TestClass
这种方法是类型安全的,但会让目标类占用更多内存,而且属性调用的函数必须为public的,另外为了让属性类能正确的取得目标类类指针,我使用了一个INIT_PROPERTY宏,这样比较麻烦,需要在构造函数中对每个属性调用一下,希望有更好办法的朋友告知.
给C++添加属性机制
最新推荐文章于 2023-02-21 21:35:41 发布