深入探究C++ 类成员(Class Members)

打印 上一主题 下一主题

主题 853|帖子 853|积分 2561

一、定义
  在class的声明里头,真正有效的两样东西是data members 和 member functions:
  Data members:表示根据这个class所产生的object里头会有些什么东西,它事实上也是占据object内存的唯一东西(除非引入虚拟机制)。通常为数据的封装性,我们把data members声明为private或protected。
  Member functions:是用来处理data members的函数。通常为了界面的开放性,我们把member functions设计为pubilc。
二、Data Members(数据成员)
  Data members的声明和一般non-class的变量声明形式一样,以CPoint为例:
  1. 1 class CPoint
  2. 2 {
  3. 3 public:
  4. 4     CPoint(float x=0.0):_x(x){}
  5. 5     
  6. 6     float x(){return _x;}
  7. 7     void x(float xval){_x=xval;}
  8. 8     
  9. 9 protected:
  10. 10     float _x;     //data member
  11. 11     
  12. 12 };
复制代码
  第10行的_x就是一个data members。
  如果data member本身不是一个变量,而是一个class object,这种环境比力特别,称为composition(组合),而这种object被称为embedded objects或object member。Composition被用来描述has a的关系(例如汽车有一个引擎),inheritance(继承)用来描述is a kind of的关系(例如汽车是一种交通工具)。稍后我们会分别描述composition和inheritance两种环境。
三、Member Functions(成员函数)
  Member functions用来处理class data members。在数据封装的环境下,member functions可以说就是一个class(或object)的对外界面。这些functions并不占用object的内存空间,它被编译器处理过后,以完全等同一般的global functions的身份出现,独立于任何object之外。同一份函数代码如何能够处理依据同一个class产生出来的差别object的data members呢?关键在于有一个this指针隐藏在member functions的参数之中,也隐藏在member functions函数代码对于data members的处理动作上,是编译器主动为我们加上去的。

 四、如何取用 Class Members
  要取得class members,如果是在class scope之内,直接使用其名称即可。但如果是在class scope之外,你有三种方式可以办到:
  1.透过dot operator(.),例如:
  1. 1 CPoint aPoint; // 产生一個 CPoint object,名为 aPoint
  2. 2 aPoint.x(); // 唤 起 CPoint::x()
  3. 3 aPoint._x = 7.0; // 使 用 CPoint 的 data member
复制代码
  2.透过arrow operator(->),例如:
  1. 1 CPoint* pPoint = new CPoint; // 产生一个 CPoint object,由 pPoint 指向它
  2. 2 pPoint->x(); // 唤 起 CPoint::x()
  3. 3 pPoint->_x = 7.0; // 使用 CPoint 的 data member
复制代码
  3.透过scope resolution operator(:,例如:
  1. 1 CPoint::foo(); // foo() must be a static member function
  2. 2 CPoint::ratio = 0.2; // ratio must be a static data member
复制代码
  第三种方法未通过任何对象访问成员,表明这些成员应属于类条理,即静态成员(Static Members)。若错误地通过对象访问非静态成员,如CPoint::foo(),将引发错误。静态成员应通过类名访问,非静态成员应通过对象实例访问。
五、特别的 Static Members(静态成员)

  Class中可以使用static关键,使members成为静态。
  静态的意思是这份members属于class而非object全部。听起来有点奇怪,因为class只是属性,而object才是实体。很难一言以敝之,让我们将members细分为data 和function来讨论。
  当你看完以下的剖析,你会认为static data members和global variables很像,static member functions和global functions 很像。一点没错,从功能而言,global 可以代替static。不外,以面对对象的观点来看,这些members如查在性质上与class痛痒相关,不是设计成class的static members为佳,面对对象的步伐设计中,我们盼望global的东西越少越好。
1. Static Data Members(静态数据成员)

  虽说data属于object实体全部,但步伐设计中有些数据也盼望由各object共享,以是提升到class层级比力理想。例如我们设计一个银行储户的class:
  1. 1 class SavingAccount
  2. 2 {
  3. 3 private:
  4. 4     char   m_name[40];//储户姓名
  5. 5     char   m_addr[60];//储户地址
  6. 6     double m_total;//账户金额
  7. 7     double m_rate;//利率
  8. 8 };
复制代码
  这家银行采用浮动利率,每个账户的利息是根据当天的利率来计算的,这时m_rate就不适合成为每个object的数据了,否则每天一开市,光把全部的账户内容调出来,修改m_rate的值,就花了不少时间。m_rate应该独立于各object之外,成为class的独一无二的数据;详细怎么做?在m_rate前面加上Static关键字就行了:
  1. 1 class SavingAccount
  2. 2 {
  3. 3 private:
  4. 4     char   m_name[40];//储户姓名
  5. 5     char   m_addr[60];//储户地址
  6. 6     double m_total;//账户金额
  7. 7     Static double m_rate;//利率(注意,这里只是声明,不是定义,未分配内存)
  8. 8 };
复制代码
  Static data members不属于object的一部份,而是class的一部份,以是步伐可以在还没有生成任何object的时候就处理Static data members。但首先,你必须定义它(为它分配内存)。
你应该在.CPP文件中且在class以外的任何区域设定其初始值,例如在main()之中,或在global function中,或任何函数之外:
  1. 1 double SavingAccount::m_rate = 0.0075; // 定义并设定初值
  2. 2 void main() // 不指定初值也可以
  3. 3 {
  4. 4 ...
  5. 5 }
复制代码
  请注意用词上的严谨:上述“定义”动作常被误以为是“初始化”动作。如果只是单纯的初值设定动作,应该可以安排在class constructor中,但上一行绝对无法如此。此外,你也不应该把上述的定义安排于.H文件中,因为这么一来它大概会被含入许多.CPP文件中,于是就重复定义了(会发生连接错误)。
  上述动作有没有思量m_rate是private数据呢?没有关系,定义static data members,不受任何封装层级的束缚。请注意上述动作也指出static data members的范例,因为这是一个定义动作,不是一个数值指定动作,如果没有做这个动作,m_rate就没有获得内存,会发生非常错误:
  1. error LNK2001: unresolved external symbol "private: static double
  2. SavingAccount::m_rate"(?m_rate@SavingAccount@@2HA)
复制代码
  下面是存取static data members的一种方式,注意:此时还没有任何object存在:
  1. 1 void main()
  2. 2 {
  3. 3 SavingAccount::m_rate = 0.0072; // 此行要成立,m_rate 需改为public
  4. 4 }
复制代码
   第二种方式是产生一个object后,透过object来处理static data members:
  1. 1 void main()
  2. 2 {
  3. 3 SavingAccount myAccount;
  4. 4 myAccount.m_rate = 0.0072; // 此行要成立,m_rate 需改为 public
  5. 5 }
复制代码
  请注意,static data members并不是因为myAccount object的实现而才得以实现,它本来就存在。因此第一种的处理方式不轻易给人错误印象;
2. Static Menber Functions(静态成员函数)
  既然static data members 是超越于object之外存在的,一般的member functions能否处理它呢?要知道,,member function得经过某个object才气调用,该object地点则成为所谓的this指针,但由于static data members并不需要靠this指针的指引来决定其地点,以是其实任何函数(包罗global函数),只要access level允许,都可以处理static data members。
  但member function得经过某个object才气调用,如果你在尚未产生任何object之前,就盼望透过某个member function来更我以为前例的static m_rate,而它又是private(以至于不能被global函数处理)那么肯定要写个static member function了:
  1. 1 class SavingAccount
  2. 2 {
  3. 3 private:
  4. 4     char   m_name[40];//储户姓名
  5. 5     char   m_addr[60];//储户地址
  6. 6     double m_total;//账户金额
  7. 7     Static double m_rate;//利率(注意,这里只是声明,未分配内存)
  8. 8 public:
  9. 9     static void setRate(double newRate){m_rate=newRate;}
  10. 10 };
  11. 11
  12. 12 double SavingAccount::m_rate=0.0072; //设初值
  13. 13
  14. 14 int main()
  15. 15 {
  16. 16     SavingAccount myAccount;
  17. 17     //可以透过object调用static member functions
  18. 18     myAccount.setRate(0.0072);
  19. 19     //也可以直接调用static memberfunction
  20. 20     SavingAccount::setRate(0.0072);
  21. 21     
  22. 22     return 0;
  23. 23 }
复制代码
  由于static member functions 不需要任何object的存就可以被调用,以是编译器不会为它暗加一个this指针。也因为如此,static member function无法处理任何non-static data members,因为member function之以是能够以单逐一份函数代码处理各个object的数据而不乱,完端赖的是this指针。
3. Static Object Members(静态对象成员)
  Object members应该被视为和一般的data members 样地位,只不外它是class范例,而一般data members是内建范例。当它冠上static,表示它所寄生的class一旦声明完成(未产生object),而且对static members做了初始化动作,这个static object member就已经在内存中有了实体。例如:
  
[code] 1 class Point3d 2 { public: 3 // ... 4 public: // (protected: is better) 5 static Point3d origin; 6 float x, y, z; 7 }; 8 Point3d Point3d:rigin; // 別忘了这个动作(其实就是实体设置) 9 10 int main()11 {12     printf("&oint3d::x = %p\n", &oint3d::x); // 0000000413     printf("&oint3d::y = %p\n", &oint3d::y); // 0000000814     printf("&oint3d::z = %p\n", &oint3d::z); // 0000000C15     printf("&oint3d:rigin = %p\n", &oint3d:rigin); // 0040A45016     printf("&oint3d:rigin.x = %p\n", &oint3d:rigin.x); // 0040A45417     printf("&Point3d:rigin.y = %p\n", &Point3d:rigin.y); // 0040A45818     printf("&Point3d:rigin.z = %p\n", &Point3d:rigin.z); // 0040A45C19     Point3d pt3d;20     cout
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表