有了get和set,那么将get和set 的具体内容(也就是那个用于返回真正值的对象)放在哪里比较好呢?
一开始,我觉得学习其他语言的那种方式不错,即把property作为一个纯粹的接口来调用,所有的东西都定位到get和set函数中去。但是,为了实现默认的get或set,方便的从一个简单的公有变量向一个受管制的property转换,我觉得说不定把内容放到property里面是一个好主意(当然也不一定)。
如果要放在里面,就存在property是应该“拥有”还是“派生自”这个对象的问题,如果考虑到get和set函数所存取的内容全部包含在property当中,那么我比较倾向于尽可能的从指定类型派生。
也就相当于这样:
namespace
rdxLib
{
template <typename Parent, typename Type>
class property_bag : public Type
{
typedef property_bag<Parent, Type> MyType;
typedef typename ::boost::call_traits<Type>::param_type param_type;
typedef typename ::boost::call_traits<Type>::reference reference;
typedef typename ::boost::call_traits<Type>::const_reference const_reference;

typedef param_type (Parent::*Get)() const;
typedef void (Parent::*Set)(param_type);

Parent * parent_;
Get getFunction_;
Set setFunction_;

public:
property_bag(const Parent * parent, Get get, Set set)
: parent_(parent)
, getFunction_(get)
, setFunction_(set)
{
}

private:
property_bag()
{
}
};
}
不过这段代码肯定有问题,因为我无法从int或Type *类型派生,它们可不是合法的对象!
那么怎么办呢……当然,要区别对待了。于是我就想到应该写一个 判断对象是否可派生的辅助类is_derivable。
namespace
rdxLib
{
namespace detail {
template <bool>
struct true_false_type_selector : public ::boost::false_type
{
};

template <>
struct true_false_type_selector<true> : public ::boost::true_type
{
};

template <typename T>
struct is_derivable_impl :
public true_false_type_selector<::boost::type_traits::ice_and<
::boost::is_class<T>::value,
::boost::is_same<T,typename::boost::remove_all_extents<T>::type>::value,
::boost::type_traits::ice_not<::boost::is_const<T>::value>::value
>::value>
{
};

template <typename T>
struct is_derivable : public is_derivable_impl<T>
{
};
}
}
明眼人一看就知道,我这是在抄boost的is_xxx系列模板类的实现,不过抄的还不像……不过总算达到差不多的功能了。其中最主要的就是is_derivable_impl的实现,如果 T是class(is_class<T>::value为true)并且 把T的所有修饰符去掉之后还是原来类型( is_same<T, typename remove_all_extents<T>::type>::value为true)并且 T没有const修饰符( ice_not<is_const<T>::value>::value为true),那么就不可继承,否则可以。这里面要注意的是:remove_all_extents<>不会去掉const修饰符,所以我必须单独为此做判断。
我对一下类型作了测试,测试代码如下:
#include
<
iostream
>
#include
<
iomanip
>
#include
<
rdx
/
property_bag.h
>

class
Sample
{}
;
//
Normal class;
class
TestClass;
//
Incomplete class.
enum
TestEnum
{a, b}
;
union TestUnion
{int c; char v;);

int main()
{
std::cout << std::boolalpha;

std::cout << ::rdxLib::detail::is_derivable<int>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<int &>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<int const>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<int *>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<int []>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<int [2]>::value << std::endl;

// Test functions.
std::cout << ::rdxLib::detail::is_derivable<int(int)>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<void (Sample::*)(int)>::value << std::endl;

// Test normal class.
std::cout << ::rdxLib::detail::is_derivable<Sample>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<Sample *>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<Sample []>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<Sample [3]>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<Sample &>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<Sample const>::value << std::endl;

// Test incomplete class.
std::cout << ::rdxLib::detail::is_derivable<TestClass>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestClass *>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestClass []>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestClass [4]>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestClass &>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestClass const>::value << std::endl;

// Test enum.
std::cout << ::rdxLib::detail::is_derivable<TestEnum>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestEnum *>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestEnum []>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestEnum [5]>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestEnum &>::value << std::endl;

// Test union.
std::cout << ::rdxLib::detail::is_derivable<TestUnion>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestUnion *>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestUnion []>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestUnion [5]>::value << std::endl;
std::cout << ::rdxLib::detail::is_derivable<TestUnion &>::value << std::endl;

return 0;
}
结果是:
再接下来就是要真正的封装对象了,下面的 basic_type_impl实现了这个功能:
namespace
rdxLib
{
namespace detail {
template <typename BasicType, bool IsObject>
class basic_type_impl;

template <typename BasicType>
class basic_type_impl<BasicType, true> : public BasicType
{
};

template <typename BasicType>
class basic_type_impl<BasicType, false>
{
BasicType value_;
};
}
}
OK,最后只要让property_bag从 basic_type_impl派生就可以了,代码如下:
namespace
rdxLib
{
template <typename Parent, typename Type>
class property_bag : public detail::basic_type_impl<Type, detail::is_derivable<Type>::value>
{
// ...
};
}
一开始,我觉得学习其他语言的那种方式不错,即把property作为一个纯粹的接口来调用,所有的东西都定位到get和set函数中去。但是,为了实现默认的get或set,方便的从一个简单的公有变量向一个受管制的property转换,我觉得说不定把内容放到property里面是一个好主意(当然也不一定)。
如果要放在里面,就存在property是应该“拥有”还是“派生自”这个对象的问题,如果考虑到get和set函数所存取的内容全部包含在property当中,那么我比较倾向于尽可能的从指定类型派生。
也就相当于这样:






























不过这段代码肯定有问题,因为我无法从int或Type *类型派生,它们可不是合法的对象!
那么怎么办呢……当然,要区别对待了。于是我就想到应该写一个 判断对象是否可派生的辅助类is_derivable。




























明眼人一看就知道,我这是在抄boost的is_xxx系列模板类的实现,不过抄的还不像……不过总算达到差不多的功能了。其中最主要的就是is_derivable_impl的实现,如果 T是class(is_class<T>::value为true)并且 把T的所有修饰符去掉之后还是原来类型( is_same<T, typename remove_all_extents<T>::type>::value为true)并且 T没有const修饰符( ice_not<is_const<T>::value>::value为true),那么就不可继承,否则可以。这里面要注意的是:remove_all_extents<>不会去掉const修饰符,所以我必须单独为此做判断。
我对一下类型作了测试,测试代码如下:
























































结果是:
false
false
false
false
false
false
false
false
true
false
false
false
false
false
true
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
其中的true对应着Sample和TestClass这两个类型,也就是说,对于普通类和未完成类(Incomplete Class),我都认为可以继承,否则不行。特别对于未完成类,我觉得不需要特殊处理,因为无论是继承还是定义变量都会报错,怎么都不能用。
false
false
false
false
false
false
false
true
false
false
false
false
false
true
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
再接下来就是要真正的封装对象了,下面的 basic_type_impl实现了这个功能:

















OK,最后只要让property_bag从 basic_type_impl派生就可以了,代码如下:






