談談c++的初始化工作(1) (轉)

amyz發表於2007-08-15
談談c++的初始化工作(1) (轉)[@more@]

  c++博大精深,這是很多瞭解c++的人的感覺。越是深入,越是覺得她會給你很好的訓練---讓你成為真正的設計者。
  我想從她的初始化工作著手,試圖展現其一角,希望能有助於您提高學c++和程式設計的興趣---然後,去發現、開拓吧,當你把你的智慧融入進去以後,一行行程式就不僅是程式了,因為它就有了生命。

  關於c中的初始化相關部分,如指標,如全域性變數與區域性變數預設初始化的區別,如靜態變數的預設初始化,就跳過。我們從類開始。
  初始化是非常重要的工作,因為你的類(確切說是,程式)的過程就是一系列狀態變換,而初態不正確,就不可能到達正確解了。
  物件導向的c++中的初始化工作,是由構造來完成的,在其他場景可能稱為構造器。這是大家都明白的。但是,展開來,或許您還未必清楚,如,如何設計好的預設初始化,哪些成員變數只有唯一的初始化形式,組合與繼承的初始化,資源淺複製問題,無名物件的問題,特殊需要的初始化(例項物件須唯一化)等等。我將在vc7.0上程式,每次除錯一個,談一個問題,試圖給您解釋清楚。願於您有所幫助。

  這次就說說好的初始化過程與靜態成員的初始化。
  不管程式設計師如何,物件導向的c++中初始化工作是必須的!!你寫了一個類,沒有寫建構函式,但是,會“暗暗的”給你一個系統預設的建構函式,在例項化物件的時候它就會工作---要知道,一旦你自己定義了建構函式,系統就不會再提供預設建構函式。
  問題是,我們應該定義自己的建構函式。否則,系統多半是無法達到正確的初始狀態的!
  定義好的建構函式,應該是給出多版本的建構函式,作好檢查工作。我們下面給出一個例子,由c++締造者的例子改動邇來。
 
  需要一個類,日期Date,它有成員變數day,month,year,執行一些相關操作。如何進行初始化工作?我們或許會見到下面的程式碼:

  //...
  class Date {
  int d,m,y;
  public:
  Date(int dd=0,int mm=0,int yy=0)
  {
  d=dd;
  m=mm;
  y=yy;
  }

  //...
  };
  //...

  這樣的程式沒有語法錯誤,可以工作,但不是正確工作。下面這個語句會怎麼樣呢?
 
  Date oneday(-2,10,2002);
  作簡單的檢查,如下面的程式碼部分。也是於事無補的。如對下面的語句仍然是無能為力的:

  Date oneday(29,2,1981);

  //...
  class Date {
  int d,m,y;
  public:
  Date(int dd=0,int mm=0,int yy=0)
  {
  if(dd>=0&&yy>=0&&mm>=0&&m<=31){//???
  d=dd;
  m=mm;
  y=yy;
  }
  //else ???
  }

  //...
  };
  //...

  更何況,我們可能會需要用string來初始化,用char *指標來初始化:
  string s="29/2/1981";
  char *p="29/2/1981";

  應該怎麼辦呢?我想你有必要好好審視你的初始化工作了!!!

  我們來看一個設計例項:
/////////////////////////////////////
//類Date(c++)
//  用於初始化工作的例子,寫於22/5/
///////////////////////////////////////////////////////////////

//date.h
#pragma once
#include
using namespace std;
enum Month{jan=1,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec};
class Date
{
  //異常類(預設建構函式,因為我們只是丟擲異常,甚至沒有標誌)
 class Bad_date{};
 int d,y;
 Month m;
  //靜態成員變數
 static Date default_date;
public:
 Date(int dd=0, Month mm=Month(0), int yy=0);

  Date(string s) { /* 省去內容*/}
  Date(char *p) { /*省去內容*/}
  ~Date(void);
 
 static void set_default(int d, Month m, int y);
 int day(void) const;
 Month month(void) const;
 int year(void) const;

 int leapyear(int y) { /*省去內容*/ return 0;}
 //...
 void Test(void);
};

  我們來看看實現部分:

//date.cpp
#include "date.h"
#using

//靜態成員的初始化
Date Date::default_date(4,feb,1981);

Date::~Date(void)
{
}
//詳盡的初始化工作的例子
Date::Date(int dd, Month mm, int yy)
{
  //(1)
 if(dd==0) dd=default_date.day();//test d=default_date.day()
 if(mm==0) mm=default_date.month();//test m=default_date.month()
 if(yy==0) yy=default_date.year();//test y=default_date.year()
  int max;

 switch(mm)
 {
 case feb:
 max=28+leapyear(yy);
 break;
 case apr:case jun:case sep:case nov:
 max=30;
 break;
 case jan:case mar:case may:case jul:case aug:case oct:case dec:
 max=31;
 break;
 default:
 throw Bad_date();
 }
 if(dd<1||max

 y=yy;
 m=mm;
 d=dd;
}

void Date::set_default(int d, Month m, int y)
{
 Date::default_date=Date(d,m,y);
}

int Date::day(void) const
{
 return d;
}

Month Date::month(void) const
{
 return m;
}

int Date::year(void) const
{
 return y;
}
//測試函式
void Date::Test(void)
{
 std::cout< <  <<:endl> std::cout<}

  這裡,有幾個需要注意的,就是:
  (1)建構函式的版本
  Date(int dd=0, Month mm=Month(0), int yy=0);
  Date(string s) { /* 省去內容*/}
  Date(char *p) { /*省去內容*/}
  (2)靜態成員提供預設的值
  //靜態成員變數
 static Date default_date;
  //及介面
  static void set_default(int d, Month m, int y);
  (3)異常管理
  //異常類(預設建構函式,因為我們只是丟擲異常,甚至沒有標誌)
 class Bad_date{};
  (4)建構函式中較好的演算法
 
  這些都是我們初始化工作交好的保證!
  用下面的程式測試,可得結果:
//fmain.cpp
#include "date.h"

void main()
{
  Date oneDay;
 oneDay.Test();
}
/*結果:

 This is a test using class Date.
 The date is(day/month/year) :4/2/1981

 Thank you!

Press any key to continue
*/

下面回到實現程式檔案date.cpp,看(1)部分的程式碼。我後面註釋了三行的程式碼。如果我用註釋的程式碼換掉程式中的程式碼,您覺得會出現什麼結果?
  這是個問題,留到下次給出答案。一箇中午就要完了,下次我將給您再詳細的談初始化工作中的其他問題。祝願您快樂的學!

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-957962/,如需轉載,請註明出處,否則將追究法律責任。

相關文章