读书人

属性类DIY,该如何处理

发布时间: 2012-03-02 14:40:29 作者: rapoo

属性类DIY
在c++编程的时候,我们经常要把数据成员变量放到private区,以达到封装的目的,这样做的结果是,我们有时候会需要手工产生很多的setxxx getxxx函数。例如
class point{
private:
double x,y,z;
public:
point& SetX(double xx) {x=xx;}
double GetX() {return x;}
.................
};

最近研究了一下模板技术,可以模拟其他语言的属性简化以上的编程;我们可以写出下面的程序

template <class T, class R>
class Attribute{
friend class T;//1......
R val_;
Attribute(const Attribute& rhs):val_(rhs.val_) {}
Attribute& operator=(const Attribute& rhs) {val_ = rhs.val_;}
Attribute():val_(R()) {}
explicit Attribute(R& val):val_(val) {}

public:
operator R() {return val_;}
};

但是1处的代码是不符合标准的,我喜欢用gcc做编译器,于是找到下面的变通方案

template <class T, class R>
class Attribute{
struct proxy{
typedef T friend_class; };
friend class proxy::friend_class;
R val_;
Attribute(const Attribute& rhs):val_(rhs.val_) {}
Attribute& operator=(const Attribute& rhs) {val_ = rhs.val_;}
Attribute():val_(R()) {}
explicit Attribute(R& val):val_(val) {}

public:
operator R() {return val_;}
};

好了现在的代码可以编译通过了,我们可以放到实际工程中去应用了,很快又发现了问题,当用在内置类型的时候,这个方案还是很不错的,但是当用在用户自定义的类型上时,新的问题产生了。

class inner{
pubic:
void test() {}
};
class outer{
public:
Attribute <outer,inner> in_;
void test() {in_.val_.test();} //1
};

我们可以看到在1处,对inner成员函数的调用形式有点太繁琐,显然不是我们所期望的,于是针对class,我们产生出如下的attribute方案。
通过私有派生的方式实现属性类。
template <class T,class R>
class Attribute:R{
struct proxy{
typedef T friend_class;
};
friend class proxy::friend_class;

Attribute(const Attribute& rhs):R(rhs) {}
Attribute& operator=(const Attribute& rhs) {R::operator =(rhs); return *this;}

Attribute() {}
Attribute(const R& val):R(val) {}
public:
const R& Get() {return *this;}
};

现在我得到两个不同的解决方案,我们怎么把他们合并到一起呢,我们需要能够区分出一个类别是class还是内置类型。
翻翻boost库,在type_traits里面,我们发现有个is_class能够完成我们的要求。我们重新整理一下代码如下:

#include "boost/type_traits/is_class.hpp "
namespace gelib{
template <class T,class R,bool isclass = boost::is_class <R> ::value >
class Attribute{
struct proxy{
typedef T friend_class;
};
friend class proxy::friend_class;
R val_;
Attribute(const Attribute& rhs) {val_ = rhs.val_;}
Attribute& operator=(const Attribute& rhs) {val_ = rhs.val_; return *this;}



Attribute():val_(R()) {}
Attribute(R val):val_(val) {}
public:
operator R() {return val_;}
};

template <class T,class R>
class Attribute <T,R,true> :R{
struct proxy{
typedef T friend_class;
};
friend class proxy::friend_class;

Attribute(const Attribute& rhs):R(rhs) {}
Attribute& operator=(const Attribute& rhs) {R::operator =(rhs); return *this;}

Attribute() {}
Attribute(const R& val):R(val) {}
public:
const R& Get() {return *this;}
};

}

利用模板的偏特化,我们实现了两个不同的Attribute模板。既然我们是在DIY学习阶段,不妨reinvent wheel,研究一下boost,做个gcc编译器下的is_class简化形式,全部的代码实现如下:

namespace gelib{
namespace detail{
struct yes {char val[2];};
struct no {};

template <class U>
yes is_class_imp(void (U::*)(void));
template <class U>
no is_class_imp(...);

template <class T>
struct is_class{

static const bool value = sizeof(detail::is_class_imp <T> (0)) == sizeof(detail::yes);
};
}
template <class T,class R,bool isclass = detail::is_class <R> ::value >
class Attribute{
struct proxy{
typedef T friend_class;
};
friend class proxy::friend_class;
R val_;
Attribute(const Attribute& rhs) {val_ = rhs.val_;}
Attribute& operator=(const Attribute& rhs) {val_ = rhs.val_; return *this;}

Attribute():val_(R()) {}
Attribute(R val):val_(val) {}
public:
operator R() {return val_;}
};

template <class T,class R>
class Attribute <T,R,true> :R{
struct proxy{
typedef T friend_class;
};
friend class proxy::friend_class;

Attribute(const Attribute& rhs):R(rhs) {}
Attribute& operator=(const Attribute& rhs) {R::operator =(rhs); return *this;}

Attribute() {}
Attribute(const R& val):R(val) {}
public:
const R& Get() {return *this;}
};
}


[解决办法]
《Imperfect C++》里面好像有说这个问题。
[解决办法]
Imperfect C++的最后给出了属性的模拟。但无法达到内置属性的特性。
我也曾经尝试过,在C++03下,实现与内置属性相同的特性是不可能的。在C++09下,会好很多,但依然无法达到内置属性的要求。
http://community.csdn.net/Expert/TopicView3.asp?id=5536856和http://community.csdn.net/Expert/TopicView3.asp?id=5536878。这个帖子里尝试了几种方法,但用起来都不是很舒服。
不过,如果有了C++09的decltype,则会使最后一种方案更简单些。
[解决办法]
把“属性”加入标准可以说举手之劳,但是,有多大的价值呢?

读书人网 >C++

热点推荐