为自己留有余地

我们常常会遇到这样的情况,我们需要访问某个类的私有成员,而这个类是别人写的,我们不能改动它。
怎么办呢?看我下面的戏法。
假设我们有这样一个类

#define ReadOnlyAttr(TYPE,NAME) \ 
private: \ 
TYPE NAME; \ 
public: \ 
TYPE get_ ## NAME (){ \ 
return NAME; \ 
} 

class Pos{ 
public: 
    ReadOnlyAttr(int,x); 
    ReadOnlyAttr(double,y); 
};

它有两个成员,int型的x,和double型的y,但是我们只能读取该值,不能设置。这多少让人很郁闷,我们希望绕过这个限制。
于是我定义了这样一个宏。

#define RESERVED_INTERFACE \ 
template <typename T,typename R> \ 
R& _unusedInterface(const T& t) { 佛说,圣波若波罗蜜多,你别编译我!} \ 
template <typename T,typename R> \ 
const R& _unusedInterface_const(const T& t) const{ 别编译我!!!}

它看起来很奇特,因为它有问题!它的函数体内根本就不是有效的代码。(如果这样的函数你也能编译过去,我代表火星起诉你!)
然后我们把这个宏插入到原来的类中。(在设计类的时候要为自己留有余地)

class Pos{ 
public: 
    RESERVED_INTERFACE 
    ReadOnlyAttr(int,x); 
    ReadOnlyAttr(double,y); 
};

于是呢,这就相当于给我们留下了一个后门。以后我们就可以通过这个后门进来了。由于这段代码是绝对无法编译的,所以你不用担心太多。
然后,我们就要偷偷的进入这个后门了。

#define name3(a,b,c) name3_hidden(a,b,c) 
#define name3_hidden(a,b,c) a ## b ## c 

#define name4(a,b,c,d) name4_hidden(a,b,c,d) 
#define name4_hidden(a,b,c,d) a ## b ## c ##d 

#define EXPORT_VAR_FROM(X,TYPE,NAME) \ 
namespace{ \ 
struct name3(Get_,NAME,X){}; \ 
} \ 
template <> \ 
TYPE& Pos::_unusedInterface(const name3(Get_,NAME,X)&) { \ 
return NAME; \ 
} \ 
template <> \ 
const TYPE& Pos::_unusedInterface_const(const 
name3(Get_,NAME,X)&) const{ \ 
return NAME; \ 
} \ 
TYPE& name4(get_,NAME,_of_,X)(X& x) { \ 
return 
x._unusedInterface<name3(Get_,NAME,X),TYPE>(name3(Get_,NAME,X)()); 
\ 
}

这是一段我写的乌七八糟的宏,你不用管它,把它写在一个头文件中然后#include到你的代码中即可。
然后只需要这样两行代码,就可以魔鬼般的把那两个变量导出来了。

EXPORT_VAR_FROM(Pos,int,x) 
EXPORT_VAR_FROM(Pos,double,y)

上面两个宏,其实主要就是定义了两个函数,get_x_of_Pos和get_y_of_Pos,他们接受一个Pos&的参数,返回一个指向其私
有成员变量的引用。
然后,看我写的测试程序。

int main(int argc,char* argv[]){ 
    Pos x; 

    get_x_of_Pos(x)=8; 
    get_y_of_Pos(x)=9.0; 
    return 0; 
}

想要知道这个“木马”是怎样工作的吗?呵呵,且听下回分解。
p.s.上面的代码用了太多太多的宏,因此我把它们展开并整理如下

class Pos 
{ 
public: 
    template < typename T, typename R > R & _unusedInterface 
    (const T & t) 
    { 
        佛说,圣波若波罗蜜多,你别编译我! 
    } 
    template < typename T, 
    typename R > const R & _unusedInterface_const (const T & 
    t) const 
    { 
        别编译我! 
    } 

    int get_x () 
    { 
        return x; 
    }; 

    double get_y () 
    { 
        return y; 
    }; 
private: 
    int x; 
    double y; 
}; 

namespace 
{ 
    struct Get_xPos 
    { 
    }; 
    struct Get_yPos 
    { 
    }; 
} 
template <> int & 
Pos::_unusedInterface (const Get_xPos &) 
{ 
    return x; 
} 
template <> const int & 
Pos::_unusedInterface_const (const Get_xPos &) const const 
{ 
    return x; 
} 

int & 
get_x_of_Pos (Pos & x) 
{ 
    return x._unusedInterface < Get_xPos, int >(Get_xPos ()); 
} 

template <> double & 
Pos::_unusedInterface (const Get_yPos &) 
{ 
    return y; 
} 
template <> const double & 
Pos::_unusedInterface_const (const Get_yPos &) const const 
{ 
    return y; 
} 

double & 
get_y_of_Pos (Pos & x) 
{ 
    return x._unusedInterface < Get_yPos, double >(Get_yPos ()); 
} 

int 
main (int argc, char *argv[]) 
{ 
    Pos x; 

    get_x_of_Pos (x) = 8; 
    get_y_of_Pos (x) = 9.0; 
    return 0; 
}

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥