• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              117 Posts :: 2 Stories :: 61 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(8)

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜


            第一個(gè)程序:
                  這個(gè)程序不是很好的,運(yùn)行的時(shí)候出現(xiàn)的一些問題,關(guān)于問題的原因注釋有闡述。第二個(gè)程序是第一個(gè)程序的修改版。第一個(gè)程序的代碼如下:

            strngbad.h文件的代碼:
            #include <iostream>
            #ifndef STRNGBAD_H_
            #define STRNGBAD_H_

            /* 這個(gè)StringBad類中的問題是由自動(dòng)定義的隱式成員函數(shù)引起的,這種函數(shù)的行為與類設(shè)計(jì)不符。
             * StringBad類中的問題是由隱式復(fù)制構(gòu)造函數(shù)和隱式復(fù)制操作符引起的。
             * 隱式地址操作符返回調(diào)用對象的地址(即this指針的值)。如果沒有提供任何構(gòu)造函數(shù),C++將創(chuàng)建
             * 默認(rèn)構(gòu)造函數(shù)。也就是說,編譯器將提供一個(gè)不接受任何參數(shù),也不執(zhí)行任何操作的構(gòu)造函數(shù),這
             * 是因?yàn)閯?chuàng)建對象時(shí)總是會(huì)調(diào)用構(gòu)造函數(shù)。如果定義了構(gòu)造函數(shù),C++將不會(huì)定義默認(rèn)構(gòu)造函數(shù)。如
             * 果希望在創(chuàng)建對象時(shí)顯式地對它進(jìn)行初始化,或需要?jiǎng)?chuàng)建對象數(shù)組時(shí),則必須顯示地定義默認(rèn)構(gòu)造
             * 函數(shù)。這種構(gòu)造函數(shù)沒有任何參數(shù),但可以使用它來設(shè)置特定的值。帶參數(shù)的構(gòu)造函數(shù)也可以是
             * 默認(rèn)構(gòu)造函數(shù),只要所有參數(shù)都有默認(rèn)值。
             
            */

            class StringBad
            {
            private:
                
            /* 這里使用char指針(而不是char數(shù)組)來表示姓名。這意味著類聲明沒有為字符串本身分配
                 * 存儲(chǔ)空間,而是在構(gòu)造函數(shù)中使用new來為字符串分配空間。這避免了在類聲明中預(yù)先定義
                 * 字符串的長度。
                 
            */

                
            char * str;    //pointer to string
                int len;    //length of string
                /* 這里,將num_strings成員聲明為靜態(tài)存儲(chǔ)類。靜態(tài)類成員有一個(gè)特點(diǎn):無論創(chuàng)建了多少對象,
                 * 程序都只創(chuàng)建一個(gè)靜態(tài)類副本。也就是說,類的所有對象共享一個(gè)靜態(tài)成員。
                 
            */

                
            static int num_strings;    //number of objects
            public:
                StringBad(
            const char * s);    //constructor
                StringBad();    //default constructor
                ~StringBad();    //destructor
                
            //friend function
                friend std::ostream & operator<<(std::ostream & os,const StringBad & st);
            }
            ;
            #endif

            strngbad.cpp文件的代碼
            #include <cstring>
            #include 
            "strngbad.h"
            using namespace std;
            /* 下面這條語句將鏡頭成員num_strings的值初始化為0。不能在類聲明中初始化靜態(tài)成員變量。
             * 這是因?yàn)槁暶髅枋隽巳绾畏峙鋬?nèi)存,但并不分配內(nèi)存。你可以使用這種格式來創(chuàng)建對象,從
             * 而分配和初始化內(nèi)存。對于靜態(tài)類成員,可以在類聲明之外使用單獨(dú)的語句來進(jìn)行初始化。
             
            */

            int StringBad::num_strings=0;

            StringBad::StringBad(
            const char * s)
            {
                len
            =strlen(s);
                str
            =new char[len+1];
                strcpy(str,s);
                num_strings
            ++;
                cout
            <<num_strings<<": \""<<str<<"\" object created\n";
            }

            StringBad::StringBad()
            {
                len
            =4;
                str
            =new char[4];
                strcpy(str,
            "C++");
                num_strings
            ++;
                cout
            <<num_strings<<": \""<<str<<"\" default object created\n";
            }

            StringBad::
            ~StringBad()
            {
                cout
            <<"\""<<str<<"\" object deleted, ";
                
            --num_strings;
                cout
            <<num_strings<<" left\n";
                
            /* delete語句是至關(guān)重要的。str成員指向new分配的內(nèi)存。當(dāng)StringBad對象過期時(shí),str指針也將過期。
                 * 但str指向的內(nèi)存仍被分配,除非使用delete將其釋放。刪除對象可以釋放對象本身占用的內(nèi)存,但并
                 * 不能自動(dòng)釋放屬于對象成員的指針指向的內(nèi)存。因此,必須使用析構(gòu)函數(shù)。在析構(gòu)函數(shù)中使用delete
                 * 語句可確保對象過期,由構(gòu)造函數(shù)使用new分配的內(nèi)存被釋放。
                 
            */

                delete [] str;
            }

            std::ostream 
            & operator<<(std::ostream & os,const StringBad & st)
            {
                os
            <<st.str;
                
            return os;
            }

            vegnews.cpp文件的代碼
            #include <iostream>
            using namespace std;
            #include 
            "strngbad.h"

            void callme1(StringBad &);
            void callme2(StringBad);

            /* 輸出中出現(xiàn)的各種非標(biāo)準(zhǔn)字符隨系統(tǒng)而異,這些字符表明,StringBad類名副其實(shí)(是一個(gè)糟糕的類)。
             * 另一種跡象是對象計(jì)數(shù)為負(fù)。在使用較新的編譯器和操作系統(tǒng)的機(jī)器上運(yùn)行時(shí),該程序通常會(huì)在顯示
             * 有關(guān)還有-1個(gè)對象的信息之前中斷,而有些這樣的機(jī)器將報(bào)告通用保護(hù)錯(cuò)誤(GPF)。GPF表明程序
             * 試圖訪問禁止它訪問的內(nèi)存單元,這是另一種糟糕的信號(hào)。
             
            */

            int main()
            {
                StringBad headline1(
            "Celery Stalks at Midnight");
                StringBad headline2(
            "Lettuce Prey");
                StringBad sports(
            "Spinach Leaves Bowl for Dollars");
                
                cout
            <<"headline1: "<<headline1<<endl;
                cout
            <<"headline2: "<<headline2<<endl;
                cout
            <<"sports: "<<sports<<endl;
                
                callme1(headline1);
                cout
            <<"headline1: "<<headline1<<endl<<endl;
                
                
            /* 這里callme2()按值(而不是引用)傳遞headline2,結(jié)果表明這是一個(gè)嚴(yán)重的問題!
                 * 這里,將headline2作為函數(shù)參數(shù)來傳遞從而導(dǎo)致析構(gòu)函數(shù)被調(diào)用。其次,雖然按
                 * 值傳遞可以防止原始參數(shù)被修改,但實(shí)際上函數(shù)已使原始字符串無法識(shí)別,導(dǎo)致
                 * 顯示一些非標(biāo)準(zhǔn)字符(顯示的具體內(nèi)存取決于內(nèi)存中包含的內(nèi)容)。
                 
            */


                
            /* 出現(xiàn)亂碼的原因在于隱式地復(fù)制構(gòu)造函數(shù)是按值進(jìn)行復(fù)制的。那么復(fù)制str的時(shí)候
                 * 復(fù)制并不是字符串,而是一個(gè)指向字符串的指針。這通常是內(nèi)存管理不善的表現(xiàn)。
                 * 解決類設(shè)計(jì)中這種問題的方法時(shí)進(jìn)行深度復(fù)制(deep copy)。也就是說,復(fù)制構(gòu)造
                 * 函數(shù)應(yīng)當(dāng)復(fù)制字符串并將副本的地址賦給str成員,而不僅僅是復(fù)制字符串地址。
                 * 這樣每個(gè)對象都有自己的字符串,而不是引用另一個(gè)對象的字符串,調(diào)用析構(gòu)函數(shù)
                 * 時(shí)都將釋放不同的字符串,而不會(huì)試圖去釋放已經(jīng)被釋放的字符串。
                 
            */

                callme2(headline2);
                cout
            <<"headline2: "<<headline2<<endl<<endl;
                
                cout
            <<"Initialize one object to another:\n";
                
            /* 這是用的是哪個(gè)構(gòu)造函數(shù)呢?不是默認(rèn)構(gòu)造函數(shù),也不是參數(shù)為const char *的構(gòu)造函數(shù)。記住,
                 * 這種形式的初始化等效于下面的語句:StringBad sailor=StringBad(sports); //constructor using sports
                 * 因?yàn)閟ports的類型為StringBad,因此相應(yīng)的構(gòu)造函數(shù)原型應(yīng)該如下:StringBad(const StringBad &);
                 * 當(dāng)使用一個(gè)對象來初始化另一個(gè)對象時(shí),編譯器將自動(dòng)生成上述構(gòu)造函數(shù)(稱為復(fù)制構(gòu)造函數(shù),因?yàn)樗鼊?chuàng)建對象
                 * 的一個(gè)副本)。自動(dòng)生成的構(gòu)造函數(shù)不知道需要更新靜態(tài)變量num_strings,因此會(huì)將計(jì)數(shù)方案搞亂。實(shí)際上,
                 * 這個(gè)例子說明的所有問題都是由編譯器自動(dòng)生成的成員函數(shù)引起的。
                 
            */

                StringBad sailor
            =sports;
                
                cout
            <<"sailor: "<<sailor<<endl;
                cout
            <<"Assign one object to another: \n";
                StringBad knot;
                knot
            =headline1;
                cout
            <<"knot: "<<knot<<endl;
                
                
            /* 因?yàn)樽詣?dòng)存儲(chǔ)對象被刪除的順序與創(chuàng)建順序相反。所以最先刪除的3個(gè)對象是knots、sailor和sport。
                 * 這里,計(jì)數(shù)變得奇怪。實(shí)際上,計(jì)數(shù)異常是一條線索。因?yàn)槊總€(gè)對象被構(gòu)造和析構(gòu)一次,因此調(diào)用
                 * 構(gòu)造函數(shù)的次數(shù)應(yīng)當(dāng)與析構(gòu)函數(shù)的調(diào)用次數(shù)相同。對象計(jì)數(shù)(num_strings)遞減的次數(shù)比遞增次數(shù)多2,
                 * 這表明使用了不將num_string遞增的構(gòu)造函數(shù)創(chuàng)建了兩個(gè)對象。類定義聲明并定義了兩個(gè)構(gòu)造函數(shù)
                 * (這兩個(gè)構(gòu)造函數(shù)都使num_strings遞增),但結(jié)果表明程序使用了3個(gè)構(gòu)造函數(shù)。
                 
            */

                cout
            <<"End of main()\n";
                
            return 0;
            }

            void callme1(StringBad & rsb)
            {
                cout
            <<"String passed by reference: \n";
                cout
            <<"    "<<rsb<<"\"\n";
            }

            void callme2(StringBad sb)
            {
                cout
            <<"String passed by value: \n";
                cout
            <<" \""<<sb<<"\"\n";
            }

            第二個(gè)程序:
                  關(guān)于類的new和delete有個(gè)較為清晰的闡述。

            string1.h文件的代碼如下:
            //string1.h -- fixed and augmented string class definition
            #include <iostream>
            using std::ostream;
            using std::istream;

            /* 如果編譯器沒有實(shí)現(xiàn)布爾類型的話,可以使用int代替bool,0代替false,1代替true。
             * 如果編譯器不支持靜態(tài)類常量,可以用枚舉來定義CINLIM。enum{CINLIM = 90};
             
            */


            #ifndef STRING1_H_
            #define STRING1_H_
            class String
            {
            private:
                
            char * str;     //pointer to string
                int len;    //length of string
                static int num_strings; //number of objects
                /* 原語句是static const int CINLIM=80;但是我的vc6編譯不通過,所以就改成這樣的形式
                 * class A
                 * {   
                 *        static const int a;   
                 * };   
                 * const int A::a = 10;
                 * 只有基本數(shù)字類型(書上說的是整型,但有些編譯器支持float等類型)的static const變量
                 * 才可以在類體內(nèi)初始化,關(guān)于static const成員變量,不同的編譯器在具體實(shí)現(xiàn)上也有些差異
                 * 定義常量只有兩種方式,一是上述的,二是enum。
                 
            */

                
            static const int CINLIM;    // cin input limit
            public:
                
            // constructors and other methods
                String(const char * s); //constructor
                String(); //default constructor
                String(const String &); //copy constructor
                ~String();
                
            int length()const {return len;}
                
            // overloaded operator methods
                String & operator=(const String &);
                String 
            & operator=(const char * s);
                
            char & operator[](int i);
                
            const char & operator[](int i)const;
                
            // overloaded operator friends
                
            // vc6對友元支持不是很好,上網(wǎng)查了一些資料,解決辦法可查看如下網(wǎng)址
                
            // http://www.shnenglu.com/kangnixi/archive/2010/02/15/107852.html
                friend bool operator< (const String &st1,const String &st2);
                friend 
            bool operator> (const String &st1,const String &st2);
                friend 
            bool operator== (const String &st1,const String &st2);
                friend ostream 
            & operator<< (ostream & os,const String & st);
                friend istream 
            & operator>> (istream & is,String & st);
                
            // static function
                static int HowMany();
            }
            ;
            #endif

            string1.cpp文件的代碼如下:
            //string1.cpp -- String class methods
            #include <cstring>
            #include 
            "string1.h"    //includes<iostream>
            using std::cin;
            using std::cout;

            // initializing static class member
            int String::num_strings = 0;
            const int String::CINLIM=80;
            // static method
            int String::HowMany()
            {
                
            return num_strings;
            }


            // class methods
            // 程序使用構(gòu)造函數(shù)String(const char *)來創(chuàng)建一個(gè)臨時(shí)String對象,其中包含temp中的字符串拷貝
            String::String(const char * s)    //construct String from C string
            {
                len 
            = strlen(s);    //set size
                str = new char[len+1]; //allot storage
                strcpy(str,s);    //initialize pointer
                num_strings++;  //set object count
            }


            /* 這是新的默認(rèn)構(gòu)造函數(shù),讀者可能會(huì)問,為什么代碼為:str = new char[1];而不是:str = new char;
             * 上面兩種方式分配的內(nèi)存量相同,區(qū)別在于前者與類析構(gòu)函數(shù)兼容,而后者不兼容。析構(gòu)函數(shù)中包含如下
             * 代碼:delete [] str;delete[]與使用new []初始化的指針和空指針都兼容。因此對于下述代碼:
             * str = new char[1];
             * str[0]='\0';
             * 可修改為:str = 0; // sets str to the null pointer
             * 對于以其他方式初始化的指針,使用delete[]時(shí),結(jié)果將是不確定的。
             
            */

            String::String()    
            //default constructor
            {
                len 
            = 4;
                str 
            = new char[1];
                str[
            0]='\0';    //default string
                num_strings++;
            }


            String::String(
            const String & st)
            {
                num_strings
            ++;    //handle static member update
                len = st.len;    //same length
                str = new char [len+1]; //allot space
                strcpy(str,st.str); //copy string to new location
            }


            String::
            ~String()    //necessary destructor
            {
                
            --num_strings;    //required
                delete [] str;    //required
            }


            // overloaded operator methods
                
                
            // assign a String to a String
            String & String::operator=(const String & st)
            {
                
            if(this == &st)
                    
            return *this;
                delete [] str;
                len
            =st.len;
                str
            =new char[len+1];
                strcpy(str,st.str);
                
            return *this;
            }


                
            // assign a C string to a String
                
            // 下面函數(shù)為提高處理效率,這樣就能夠直接使用常規(guī)字符串,不用創(chuàng)建和刪除臨時(shí)對象了。
            String & String::operator=(const char * s)
            {
                
            // 一般來說,必須釋放str指向的內(nèi)存,并為新字符串分配足夠的內(nèi)存。
                delete [] str;
                len 
            =strlen(s);
                str
            =new char[len+1];
                strcpy(str,s);
                
            return *this;
            }


                
            // read-write char access for non-const String
            char & String::operator[](int i)
            {
                
            return str[i];
            }

                
                
            //read-only char access for const String
            const char & String::operator[](int i)const
            {
                
            return str[i];
            }


            //overloaded operator friends
            /* 要實(shí)現(xiàn)字符串比較函數(shù),最簡單的方法是使用標(biāo)準(zhǔn)的strcmp()函數(shù)。如果按照字母順序,
             * 第一個(gè)參數(shù)位于第二個(gè)參數(shù)之前,則該函數(shù)返回一個(gè)負(fù)值;如果兩個(gè)字符串相同,則返回
             * 0;如果第一個(gè)參數(shù)位于第二個(gè)參數(shù)之后,則返回一個(gè)正值
             
            */

            bool operator<(const String &st1,const String &st2)
            {
                
            return(strcmp(st1.str,st2.str)<0);
            }

            bool operator>(const String &st1,const String &st2)
            {
                
            return st2.str<st1.str;
            }

            bool operator==(const String &st1,const String &st2)
            {
                
            return(strcmp(st1.str,st2.str)==0);
            }

                
            // simple String output
            ostream & operator<<(ostream & os,const String & st)
            {
                os
            <<st.str;
                
            return os;
            }

                
            // quick and dirty String input
                /* 重載>>操作符提供了一種將鍵盤輸入行讀入到String對象中的簡單方法。它假定輸入的字符數(shù)不多于
                 * String::CINLIM的字符數(shù),并丟棄多余的字符。在if條件下,如果由于某種原因(如到達(dá)文件尾,或
                 * get(char *,int)讀取的是一個(gè)空行)導(dǎo)致輸入失敗,istream對象的值將置為false。
                 
            */

            istream 
            & operator>> (istream & is,String & st)
            {
                
            char temp[String::CINLIM];
                
            is.get(temp,String::CINLIM);
                
            if(is)
                    st
            =temp;
                
            // 上面的式子在vc6編譯下,發(fā)生如下錯(cuò)誤代碼
                
            // error C2678: binary '=' : no operator defined which takes a left-hand operand 
                
            // of type 'const class String' (or there is no acceptable conversion)
                
            // 原來是我不小心看錯(cuò),將st聲明為const String &類型了
                while(is && is.get()!= '\n')
                    
            continue;
                
            return is;
            }

            saying1.cpp文件的代碼如下:
            // saying1.cpp -- using expanded String class
            // compile with string1.cpp
            #include <iostream>
            #include 
            "string1.h"
            using namespace std;
            const int ArSize = 10;
            const int MaxLen = 81;
            int main()
            {
                String name;
                cout
            <<"Hi, what's your name?\n>> ";
                cin
            >>name;

                cout
            <<name<<", please enter up to "<<ArSize<<" short sayings <empty line to quit>:\n";
                String sayings[ArSize];    
            //array of objects
                char temp[MaxLen];    //temporary string storage
                int i;
                
            for(i=0;i<ArSize;i++)
                
            {
                    
            /* 較早的get(char *,int)版本在讀取空行后,返回的值不為false。不過,對于這些版本來說
                     * 如果讀取了一個(gè)空行,則字符串中第一個(gè)字符將是一個(gè)空字符。這個(gè)范例使用了下述代碼:
                     * if(!cin||temp[0]=='\0')    //empty line?
                     *        break;                //i not incremented
                     * 如果實(shí)現(xiàn)遵循了最新的C++標(biāo)準(zhǔn),則if語句中的第一個(gè)條件將檢測到空行,第二個(gè)條件用于
                     * 舊版本實(shí)現(xiàn)中檢測空行。
                     
            */

                    cout
            <<i+1<<"";
                    cin.
            get(temp,MaxLen);
                    
            while(cin && cin.get()!='\n')
                        
            continue;
                    
            if(!cin || temp[0== '\0')    // empty line
                        break;    //i not incremented
                    else
                        sayings[i]
            =temp;    //overloaded assignment
                }

                
            int total=i;    //total # of lines read

                cout
            <<"Here are your sayings:\n";
                
            for(i=0;i<total;i++)
                    cout
            <<sayings[i][0]<<""<<sayings[i]<<endl;

                
            int shortest=0;
                
            int first=0;
                
            for(i=1;i<total;i++)
                
            {
                    
            if(sayings[i].length()<sayings[shortest].length())
                        shortest
            =i;
                    
            if(sayings[i]<sayings[first])
                        first
            =i;
                }

                cout
            <<"Shortest saying:\n"<<sayings[shortest]<<endl;
                cout
            <<"First alphabetically:\n"<<sayings[first]<<endl;
                cout
            <<"This program used "<<String::HowMany()<<" String objects. Bye.\n";

                
            return 0;
            }

            posted on 2010-02-14 23:01 煙皚 閱讀(951) 評論(0)  編輯 收藏 引用 所屬分類: C++ primer plus學(xué)習(xí)筆記
            国产精品99久久久久久猫咪| 久久亚洲中文字幕精品有坂深雪| 99久久国语露脸精品国产| 中文字幕精品久久久久人妻| 国产精品伦理久久久久久| 久久久久亚洲av无码专区喷水 | 精品无码久久久久久国产| 国内精品久久久久久99蜜桃 | 亚洲国产视频久久| 久久精品国产一区二区三区不卡| 久久婷婷五月综合97色直播| 久久精品国产亚洲欧美| 91精品国产乱码久久久久久| 国内精品久久久久久久97牛牛| 久久av无码专区亚洲av桃花岛| 久久亚洲精品人成综合网| 成人妇女免费播放久久久| 99久久国产热无码精品免费| 久久96国产精品久久久| 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲 | www久久久天天com| 久久国产精品一区二区| 国产成人香蕉久久久久| 久久人妻少妇嫩草AV无码蜜桃| 午夜精品久久久久久影视777| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区| 欧美精品丝袜久久久中文字幕| 午夜精品久久久久成人| 亚洲精品乱码久久久久久久久久久久| 久久偷看各类wc女厕嘘嘘 | 久久国产香蕉视频| 综合久久给合久久狠狠狠97色| 青草国产精品久久久久久| 久久精品中文字幕久久| 免费一级做a爰片久久毛片潮| 欧美黑人激情性久久| 69国产成人综合久久精品| 久久99亚洲综合精品首页| 久久99精品久久久大学生| 99久久99久久精品免费看蜜桃| 久久精品国产一区二区|