友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第183章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




  const char* name() const { return nm; }  

  const char* value() const { return val; }  

  // Test for 〃emptiness〃  

  bool empty() const {  

    return (nm == 0) || (val == 0);  

  }  

  // Automatic type conversion for boolean test:  

  operator bool() const {  

    return (nm != 0) && (val != 0);  

  }  

  // The following constructors & destructor are  

  // necessary for bookkeeping in C++。  

  // Copy…constructor:  

  Pair(const Pair& p) {  

    if(p。nm == 0 || p。val == 0) {  

      nm = val = 0;  

    } else {  

      // Create storage & copy rhs values:  

      nm = new char'strlen(p。nm) + 1';  

      strcpy(nm; p。nm);  

      val = new char'strlen(p。val) + 1';  

      strcpy(val; p。val);  

    }  

  }  

  // Assignment operator:  

  Pair& operator=(const Pair& p) {  

    // Clean up old lvalues:  

    delete nm;  

    delete val;  

    if(p。nm == 0 || p。val == 0) {  



                                                                                          567 


…………………………………………………………Page 569……………………………………………………………

      nm = val = 0;  

    } else {  

      // Create storage & copy rhs values:  

      nm = new char'strlen(p。nm) + 1';  

      strcpy(nm; p。nm);  

      val = new char'strlen(p。val) + 1';  

      strcpy(val; p。val);  

    }  

    return *this;  

  }   

  ~Pair() { // Destructor  

    delete nm; // 0 value OK  

    delete val;  

  }  

  // If you use this method outide this class;   

  // you're responsible for calling 'delete' on  

  // the pointer that's returned:  

  static char*   

  decodeURLString(const char* URLstr) {  

    int len = strlen(URLstr);  

    char* result = new char'len + 1';  

    memset(result; len + 1; 0);  

    for(int i = 0; j = 0; i = 'A')  

      return (hex & 0xdf) 'A' + 10;  

    else  

      return hex '0';  

  }  

};  

  

// Parses any CGI query and turns it  

// into an STL vector of Pair objects:  

class CGI_vector : public vector {  

  char* qry;  

  const char* start; // Save starting position  

  // Prevent assignment and copy…construction:  

  void operator=(CGI_vector&);  



                                                                                               568 


…………………………………………………………Page 570……………………………………………………………

  CGI_vector(CGI_vector&);  

public:  

  // const fields must be initialized in the C++  

  // 〃Constructor initializer list〃:  

  CGI_vector(char* query) :  

      start(new char'strlen(query) + 1') {  

    qry = (char*)start; // Cast to non…const  

    strcpy(qry; query);  

    Pair p;  

    while((p = nextPair()) != 0)  

      push_back(p);  

  }  

  // Destructor:  

  ~CGI_vector() { delete start; }  

private:  

  // Produces name…value pairs from the query   

  // string。 Returns an empty Pair when there's   

  // no more query string left:  

  Pair nextPair() {  

    char* name = qry;  

    if(name == 0 || *name == '0')  

      return Pair(); // End; return null Pair  

    char* value = strchr(name; '=');  

    if(value == 0)  

      return Pair(); // Error; return null Pair  

    // Null…terminate name; move value to start  

    // of its set of characters:  

    *value = '0';  

    value++;  

    // Look for end of value; marked by '&':  

    qry = strchr(value; '&');  

    if(qry == 0) qry = 〃〃; // Last pair found  

    else {  

      *qry = '0'; // Terminate value string  

      qry++; // Move to next pair  

    }  

    return Pair(name; value);  

  }  

}; ///:~  

  

在#include 语句后,可看到有一行是:  

using namespace std;  

C++中的“命名空间”(Namespace)解决了由Java 的package 负责的一个问题:将库名隐藏起来。std命名 

空间引用的是标准C++库,而 vector 就在这个库中,所以这一行是必需的。  

Pair 类表面看异常简单,只是容纳了两个(private)字符指针而已——一个用于名字,另一个用于值。默 

认构建器将这两个指针简单地设为零。这是由于在 C++中,对象的内存不会自动置零。第二个构建器调用方 

法 decodeURLString(),在新分配的堆内存中生成一个解码过后的字串。这个内存区域必须由对象负责管理 

及清除,这与“破坏器”中见到的相同。name()和 value()方法为相关的字段产生只读指针。利用 empty()方 

法,我们查询Pair 对象它的某个字段是否为空;返回的结果是一个 bool——C++内建的基本布尔数据类型。 

operator bool()使用的是 C++ “运算符过载”的一种特殊形式。它允许我们控制自动类型转换。如果有一个 

名为p 的Pair 对象,而且在一个本来希望是布尔结果的表达式中使用,比如 if(p){//。。。,那么编译器能辨 

别出它有一个Pair,而且需要的是个布尔值,所以自动调用 operator bool(),进行必要的转换。  



                                                                                         569 


…………………………………………………………Page 571……………………………………………………………

接下来的三个方法属于常规编码,在C++中创建类时必须用到它们。根据C++类采用的所谓“经典形式”,我 

们必须定义必要的“原始”构建器,以及一个副本构建器和赋值运算符——operator= (以及破坏器,用于清 

除内存)。之所以要作这样的定义,是由于编译器会“默默”地调用它们。在对象传入、传出一个函数的时 

候,需要调用副本构建器;而在分配对象时,需要调用赋值运算符。只有真正掌握了副本构建器和赋值运算 

符的工作原理,才能在 C++里写出真正“健壮”的类,但这需要需要一个比较艰苦的过程(注释⑤)。  

  

⑤:我的《Thinking in C++》(Prentice…Hall;1995)用了一整章的地方来讨论这个主题。若需更多的帮 

助,请务必看看那一章。  

  

只要将一个对象按值传入或传出函数,就会自动调用副本构建器Pair(const Pair&)。也就是说,对于准备 

为其制作一个完整副本的那个对象,我们不准备在函数框架中传递它的地址。这并不是Java 提供的一个选 

项,由于我们只能传递句柄,所以在Java 里没有所谓的副本构建器(如果想制作一个本地副本,可以“克 

隆”那个对象——使用 clone(),参见第12 章)。类似地,如果在 Java 里分配一个句柄,它会简单地复 

制。但 C++中的赋值意味着整个对象都会复制。在副本构建器中,我们创建新的存储空间,并复制原始数 

据。但对于赋值运算符,我们必须在分配新存储空间之前释放老存储空间。我们要见到的也许是 C++类最复 

杂的一种情况,但那正是Java 的支持者们论证Java 比C++简单得多的有力证据。在 Java 中,我们可以自由 

传递句柄,善后工作则由垃圾收集器负责,所以可以轻松许多。  

但事情并没有完。Pair 类为nm 和 val 使用的是char*,最复杂的情况主要是围绕指针展开的。如果用较时髦 

的C++ string 类来代替char*,事情就要变得简单得多(当然,并不是所有编译器都提供了对 string 的支 

持)。那么,Pair 的第一部分看起来就象下面这样:  

  

class Pair {  

  string nm;  

  string val;  

public:  

  Pair() { }  

  Pair(char* name; char* value) {  

    nm = decodeURLString(name);  

    val = decodeURLString(value);  

  }  

  const char* name() const { return nm。c_str(); }  

  const char* value() const {   

    return val。c_str();   

  }  

  // Test for 〃emptiness〃  

  bool empty() const {  

    return (nm。length() == 0)   

      || (val。length() == 0);  

  }  

  // Automatic type conversion for boolean test:  

  operator bool() const {  

    return (nm。length() != 0)   

      && (val。length() != 0);  

  }  

  

 (此外,对这个类decodeURLString()会返回一个 string,而不是一个char*)。我们不必定义副本构建 

器、operator=或者破坏器,因为编译器已帮我们做了,而且做得非常好。但即使有些事情是自动进行的, 

C++程序员也必须了解副本构建以及赋值的细节。  

Pair 类剩下的部分由两个方法构成:decodeURLString()以及一个“帮助器”方法translateHex()——将由 

decodeURLString()使用。注意 translateHex()并不能防范用户的恶意输入,比如“%1H”。分配好足够的存 

储空间后(必须由破坏器释放),decodeURLString()就会
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!