C++(对象模型):04---Data Member的绑定(类内成员与全局数据的冲突性问题)

一、考察下面的一个例子

//某个foo.h头文件,有如下声明
extern float x;
//在Point3d.h文件中

#include "foo.h"
class Point3d
{
public:
    Point3d(float, float, float);

    //问题:这里返回的是哪一个x哪?
    float X()const { return x; }
    void X(float new_X) { x = new_X; }
    //...
private:
    float x, y, z;
};

问题思考

  • 在上面的Point3d.h头文件中,第一个X()成员函数会返回什么哪?class外部的(x)哪?还是class内部的数据成员x哪?

问题解析

  • 在今天看来,第一个X()成员函数时内部的x数据成员

二、早期C++标准的数据成员绑定

  • 为了防止类内数据成员与全局数据成员产生冲突,早期C++设置了下面两种防御性程序设计风格

风格①

  • 把所有的数据成员放在class声明起头处,以确保正确的绑定
#include "foo.h"
class Point3d
{
    float x, y, z;
public:
    //...
    float X()const { return x; }
    //...
};

风格②

  • 把所有的内联函数,不管大小都放在class声明之外
#include "foo.h"
class Point3d
{
    float x, y, z;
public:
    //...
    float X()const;
    //...
};

inline float Point3d::X()const
{
    return x;
}
  • 总结:上面这种设计风格到今天还存在,虽然在C++2.0之后这种必要性就消失了。这些古老的语言规则被称为“member rewriting rule”,大意是“一个inline函数,在整个class声明未被完全看见之前,是不会被评估求值的”

三、现代C++标准的数据成员绑定规则

  • C++标准精炼上面的“rewriting rule”,定义了如下的规则:
    • 对数据成员的分析,只有在整个class的声明都出现了才开始(直到出现classs右大花括号“}”)

演示说明

extern int x;

class Point3d
{
public:
    //...
    //该函数本身的分析不会立即执行,而是等到class声明的右大括号“}”出现才开始
    float X()const { return x; }
    //...
private:
        float x, y, z;
};
//在此,class的分析才开始,所以X()成员函数分析的是自身类的x数据成员,而不是全局的x

四、参数列表分析

  • 通过下面这些演示案例,为了说明本文所介绍的“Data Member的绑定”是与数据成员有关的规则,而其他规则则不可以使用,需要具体分析
  • 参数列表的规则与上面的数据成员分析规则有一些不一样(请看下面的演示案例)

演示案例①

  •  尽管类型也使用typedef进行了类型声明,但是两个mumble成员函数使用的都是全局的typedef声明
typedef int length;//全局

class Point3d
{
public:
	void mumble(length val) { _val = val; }
	length mumble() { return _val; }
private:
	typedef float length; //局部
	length _val;
};

演示案例②

  •  为了演示上面那个演示案例的正确性,我们将全局typedef注释掉,程序会报错
//typedef int length;

class Point3d
{
public:
	void mumble(length val) { _val = val; }
	length mumble() { return _val; }
private:
	typedef float length; //局部
	length _val;
};

演示案例③

  • 为了正确使用类内的typedef声明,我们应该将类内typedef放置在class声明的最前面
  • 下面的程序是语义正确的
typedef int length; //全局

class Point3d
{
private:
	typedef float length; //局部
	length _val;
public:
	void mumble(length val) { _val = val; }
	length mumble() { return _val; 
};
发布了1300 篇原创文章 · 获赞 827 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/103807683