Data Member 的绑定

考察以下代码:

extern float _x;

//user code
class Point3d
{
public:
    Point3d(float, float, float);
    //问题来了, 是哪一个 _x?
    float X() const {return _x;}
    void  X(float x) const { _x = x;}
private:
    float _x, _y, _z;
};

许多人可能会说, 应该是 class 中的 _x,但是很难保证在不同的编译器上行为一致, 因此就有了以下两种防御性的设计风格:

class Point3d
{
    //#1
    //在 class 声明的起头处放置所有的 data member
    float x, y, z;
public:
    float X() const {return _x;}
    //...
};

class Point3d
{
    //#2
    //把 inline 移到 class 之外
    Point3d();
    float X() const;
    void X(float) const;
    //...
};

inline float
Point3d:: X() const {return _x;}

这种风格至今存在, 但已不是必要手段, C++ 2.0 之后, 有了这样一个规则:如果一个 inline 函数实体在整个 class 声明未被看见之前, 是不会被评估求值的。也就是说, 考察以下代码:

extern int _x;

class Point3d
{
public:
    //对于函数本身的分析将延迟
    //直到 class 声明的右大括号出现才开始
    float X() const {return _x;}
private:
    float _x;
};
//事实上, 对 class 的分析从这才刚开始

因此,在一个 inline member function 躯体之内的一个 data member 绑定操作, 会在整个 class 声明后才发生。
但是, 这对于 member function 的 argument list 并不为真。Argument list 中的名称还是会在它们第一次遭遇时被适当地 resolve。 因此在 extern 和 nested type names 之间的非直觉绑定还是会发生, 考察以下代码:

typedef int length;

class Point3d
{
public:
    //wtf!length 被 resolve 为 global
    //没问题, _val 被 resolve 为 Pointd::_val
    void mumble(length val) {_val = val;}    //此处在接下来 定义 length 后会被认定不合法
    length mumble() {return _val;}
    //...
private:
    //length 必须在此 class 对它的第一个参考操作之前被发现
    //这样就导致编译器显示先前的参考操作不合法
    typedef float length;
    length _val;
};

在这样的情况下, 就需要之前的防御风格: 把 nwsted type 声明放在 class 的起始处, 就可以避免导致的非直觉绑定。

posted @ 2014-11-17 21:47  wu_overflow  阅读(223)  评论(0编辑  收藏  举报