C++类中定义数据成员的类型的几种方式

来源:互联网 发布:阿里云系统盘满了 编辑:程序博客网 时间:2024/05/17 04:13

时间:2014.04.04

地点:基地二楼

—————————————————————

一、简述

C++中除了在类中简单声明数据成员外,还可创建static数据成员,const成员,引用成员,const引用等。

—————————————————————

二、.静态数据成员

 应用背景:有时没必要让所有类的对象都包含某个变量的副本,或者说你需要一个只对类有意义的数据成员,而不适用于针对某个对象。比如设计一个电子表格的类,每个电子表格都有一个唯一的ID,我们可以为类设计一个从0开始的计数器,这样每个对象可从这个计数器得到自身的ID,但显然没必要为每个对象包含这个计数器,这样的麻烦是因为你还得让计数器保持同步。解决的办法是使用静态数据成员。静态数据成员属于类,而不具体属于类的某个实例,可将静态数据成员当做属于类的全局变量,所有该类的实例对象都只有和可见这么一份。比如:

class MyClass{    //......   protected:      static int counter_=0;}
注意:在C++11中是可以在类的定义中初始化静态成员的。下面介绍具体的两个用法

1.在类的方法内访问静态数据成员

在类的方法内部可像使用普通数据成员一样使用静态数据成员。比如:

类的声明部分:

class MyClass{  public:    //.....    int get_id() const;  protected:    //.....    static int count=0;    int id_;};

类的实现部分:

MyClass::MyClass(int in_width,int int height):width_(in_width),height_(height){  id_=count++;   //......}
也就是说在构造函数中可以访问静态数据成员counter就像访问普通数据成员一样。

2.在方法外访问静态数据成员

访问控制限定符也适用于静态数据成员。上面的counter是protected的,因此不能在类外访问,若是公有的则可,具体也是用作用域解析运算符指出这个变量是类的一部分,例如:

int i=MyClass::count;
当然,并不建议这么用,而是为类提供get/set方法来授权访问权限。如果想要访问静态数据成员,应该提供静态的get/set方法。

—————————————————————

三、常量数据成员

  类的数据成员还可以声明为cosnt,这意味着在创建并初始化之后数据成员的值不能再改变。然而在对象层次上常量通常没有意义,因此常量数据成员通常也是静态的。如果某个常量只适用于类,应该使用静态常量数据成员而不是全局常量。例如设计一个表格类时,我们可能会指定表格表格的最大高度和宽度,这个值可设置成一个静态常量数据成员,当用户想要创建的表格高度或宽度大于该最大值时使用最大值,代码片段如下:

class SpreedSheet{  public:     //......     static const int kMaxHeight=100;     static const int kMaxWidth=100;};
为什么说在对象层次上常量通常没有意义呢,私下认为,对象本身就是个变量,但对象里面却包含常量很不可思议,是不?换句话说:变得东西里含有不变的成分,那么不变的那部分还有什么意义呢。

有了上述类中的静态常量,我们就可以在类的构造函数中这样使用这个新的常量了。

SpreedSheet::SpreadSheet(int width,int hegiy):  width_(width<kMaxWidth?width:kMaxWidth),  height(height<kMaxHeight?height:kMaxHight){  id_=count++;   //......}
这样当输入宽度或高度大于最大值时,会自动使用最大高度和宽度构造对象。由于kMaxHeight以及kMaxWith是公有的,因此可在程序的任何位置对其进行访问。但必须带作用域解析符,以说明该变量是哪个类的一部分。例:

cout<<SpreadSheet::kMaxHeight<<endl;

—————————————————————

四、引用数据成员

  考虑一个架构问题:电子表格如何与应用程序通信?至少我们应该让应用程序存储电子表格,电子表格也该存储应用程序对象的引用。即具体来说SpreadSheet类必须知道SpreadSheetApplication类,SpreadsheetApplication类也必须知道SpreadSheet类,即通信是双方的,必须相互认识才能有效传递消息么。那么这里就存在一个问题,我们在类的实现里需要相互#inlcude,这就是传说中的循环引用问题,相互#include是不能解决问题的。解决方案是在其中一个头文件中使用前置声明。比如下面含前置声明的类的定义:

class SpreadsheetApplication;  //前置声明classSpreadsheet{  public:      Spreadsheet(int in_width,Int in_height,SpreadsheetApplication& the_app);       //......  protected:      //......      SpreadsheetApplication& the_app_;};
这里类的定义将一个SpreadsheetApplicatin引用作为数据成员添加进来,建议使用引用,因为引用总是引用一个SpreadsheetApplication,而指针无法保证这点。在类的构造函数中,每个Spreeadsheet都得到一个应用程序的引用。若不引用某些事物,引用将无法存在,因此在构造函数中必须给the_app_一个值。

Spreadsheet::Spreadsheet(int in_width,int in_height,SpreadsheetApplication & the_app):widthe_(in_width<kMaxWidth?in_width:kMaxWidth),height_(in_height<kMaxHeight?in_height:kMaxHight),the_app_(the_app){}
也就是说类中的引用数据成员必须在类的所以构造函数中初始化它。包括复制构造函数:

Spreeadsheet::Spreadsheet(const Spreadsheet& src):                            the_app_(src.the_app_){}

在初始化一个引用之后,不能改变它的引用对象。因此无需在赋值运算符中对引用赋值。

—————————————————————

五、常量引用数据成员

  和普通引用可以引用常量对象一样,引用成员也可以引用常量对象。可以这么看,常量不过是普通的一个特殊而已。例如:

class Spreadsheet{  public:    Spreadsheet(int in_width,int in_height,const SpreadsheetApplication& the_app);    //......  protected:    //......  const SpreadsheetApplication& the_app_;};
常量引用和非常量引用的一个重要区别是:比如这里的常量引用SpreadsheetApplication的数据成员 the_app_只能调用SpreadsheetApplication对象上的常量方法。如果试图通过常量引用调用非常量方法,编译报错。







0 0
原创粉丝点击