2016年計(jì)算機(jī)二級(jí)考試C++復(fù)習(xí)資料:類的其他幾點(diǎn)問題

字號(hào):


    一、拷貝構(gòu)造函數(shù)   拷貝構(gòu)造函數(shù)在下列情況下被調(diào)用:用已經(jīng)存在的對(duì)象去初始化同一個(gè)類的另一個(gè)對(duì)象;在函數(shù)的參數(shù)中,以傳值方式傳遞類對(duì)象的拷貝;類對(duì)象的值被用做函數(shù)的返回值??截悩?gòu)造函數(shù)和前面說到的轉(zhuǎn)換構(gòu)造函數(shù)有些相似。轉(zhuǎn)換構(gòu)造函數(shù)是把一個(gè)類的對(duì)象轉(zhuǎn)化為另一個(gè)類的對(duì)象;拷貝構(gòu)造函數(shù)是用一個(gè)已經(jīng)存在的對(duì)象的值實(shí)例化該類的一個(gè)新對(duì)象。   不同對(duì)象間的初始化和賦值的區(qū)別:賦值操作是在兩個(gè)已經(jīng)存在的對(duì)象間進(jìn)行的;而初始化是要?jiǎng)?chuàng)建一個(gè)新的對(duì)象,并且其初值來源于另一個(gè)已存在的對(duì)象。編譯器會(huì)區(qū)別這兩種情況,賦值的時(shí)候調(diào)用重載的賦值運(yùn)算符,初始化的時(shí)候調(diào)用拷貝構(gòu)造函數(shù)。   如果類中沒有拷貝構(gòu)造函數(shù),則編譯器會(huì)提供一個(gè)默認(rèn)的。這個(gè)默認(rèn)的拷貝構(gòu)造函數(shù)只是簡(jiǎn)單地復(fù)制類中的每個(gè)成員。    #include iostream.h    #include string.h    class Date    {    int mo, da, yr;    char* month;    public:    Date(int m = 0, int d = 0, int y = 0);    Date(const Date &);    ~Date();    void display() const;    };    Date::Date(int m, int d, int y)    {    static char* mos[] =    {    January, February, March, April, May, June,    July, August, September, October, November, December    };    mo = m; da = d; yr = y;    if (m != 0)    {    month = new char[strlen(mos[m-1])+1];    strcpy(month, mos[m-1]);    }    else    month = 0;    }    Date::Date(const Date & dt)    {    mo = dt.mo;    da = dt.da;    yr = dt.yr;    if (dt.month != 0)    {    month = new char [strlen(dt.month)+1];    strcpy(month, dt.month);    }    else    month = 0;    }    Date::~Date()    {    delete [] month;    }    void Date::display() const    {    if (month != 0)    cout << month <<' '<< da << , << yr << std::endl;    }    int main()    {    Date birthday(6,24,1940);    birthday.display();    Date newday = birthday;    newday.display();    Date lastday(birthday);    lastday.display();    return 0;    }   本例中,用到了兩次拷貝構(gòu)造函數(shù)。一個(gè)是使用普通的C++初始化變量的語句:    Date newday = birthday;   另一個(gè)是使用構(gòu)造函數(shù)的調(diào)用約定,即把初始化值作為函數(shù)的參數(shù):    Date lastday(birthday);
    二、類的引用   在函數(shù)參數(shù)和返回值中,如果一定要使用傳值方式,那么使用類對(duì)象的引用,是一個(gè)提高效率的方法。   類的數(shù)據(jù)成員也可以是一個(gè)引用,但必須注意:第一,一個(gè)引用必須初始化。通常一個(gè)類對(duì)象并不會(huì)像結(jié)構(gòu)那樣用大括號(hào)來初始化,而是調(diào)用構(gòu)造函數(shù)。因此在構(gòu)造函數(shù)里必須初始化類當(dāng)中的引用成員。第二,引用是一個(gè)別名。盡管類里面的引用在使用方式上看起來和類的一般數(shù)據(jù)成員沒有什么區(qū)別,但是作用在其上的操作,實(shí)際上是對(duì)用來初始化它的那么對(duì)象進(jìn)行的。    #include iostream.h    class Date    {    int da, mo, yr;    public:    Date(int d,int m,int y)    { da = d; mo = m; yr = y; }    void Display() const    { cout << da << '/' << mo << '/' << yr; }    };    class Time    {    int hr, min, sec;    public:    Time(int h, int m, int s)    { hr = h; min = m; sec = s; }    void Display() const    { cout << hr << ':' << min << ':' << sec; }    };    class DateTime    {    const Date & dt;    const Time & tm;    public:    DateTime(const Date & d, const Time& t) : dt(d), tm(t)    {    //empty    }    void Display() const    {    dt.Display();    cout << ' ';    tm.Display();    }    };    int main()    {    Date today(7,4,2004);    Time now(15,20,0);    DateTime dtm(today, now);    dtm.Display();    return 0;    }   我們來看看這個(gè)程序中DateTime的構(gòu)造函數(shù)的格式:冒號(hào)操作符引出了一個(gè)參數(shù)初始化表。必須使用這種格式來初始化引用數(shù)據(jù)成員,而不可以在函數(shù)體內(nèi)來進(jìn)行初始化工作。如果構(gòu)造函數(shù)像上例一樣不是內(nèi)聯(lián)的,那么不要在類聲明中構(gòu)造函數(shù)的原型上使用冒號(hào)和初始化值表,而是像下面這樣,把參數(shù)初始化表放在定義構(gòu)造函數(shù)的地方:    Class DateTime    {    const Date & dt;    const Time & tm;    public:    DateTime(const Date & d,const Time& t);    }    DateTime::DateTime(const Date & d,const Time& t):dt(d),tm(t)    {    //empty    }   可以使用構(gòu)造函數(shù)的參數(shù)初始化表來初始化任何數(shù)據(jù)成員。特別是常量數(shù)據(jù)成員,和引用一樣,只能在參數(shù)初始化表里進(jìn)行初始化,這是因?yàn)椴豢梢栽跇?gòu)造函數(shù)內(nèi)部為常量數(shù)據(jù)成員賦值。   當(dāng)一個(gè)類含有引用數(shù)據(jù)成員時(shí),一旦引用被實(shí)例化和初始化以后,就無法修改它的值,所以該類不可能徹底地重載賦值運(yùn)算符函數(shù)。
    三、構(gòu)造函數(shù)的參數(shù)初始化表   如果類對(duì)象的某些數(shù)據(jù)成員沒有載構(gòu)造函數(shù)內(nèi)部被初始化,那么必須使用構(gòu)造函數(shù)的參數(shù)初始化表對(duì)他們進(jìn)行初始化。否則,編譯器不止到該如何初始化這些還等著在構(gòu)造函數(shù)內(nèi)部賦值的成員。我們習(xí)慣用參數(shù)初始化表來初始化所有數(shù)據(jù)成員。    class Date    {    int mo,da,yr;    public:    Date(int m=0,int d=0,int y=0);    };    class Employee    {    int empno;    Date datehired;    public:    Employee(int en,Date & dh);    };   可以用下面兩種方法編寫Employee類的構(gòu)造函數(shù):    Employee::Employee(int en,Date & dt)    {    empno=en;    datehired=dh;    }   或者;    Employee::Employee(int en,Date & dt):empno(en),datehired(dh)    {    //empty    }   雖然這兩種方法效果是一樣的,但是根據(jù)Date對(duì)象默認(rèn)構(gòu)造函數(shù)的復(fù)雜性的不同,這兩種形式的效率差別是很大的。
    四、對(duì)const修飾符的簡(jiǎn)單說明   如果一個(gè)對(duì)象被聲明為常量,那么該對(duì)象就不可以調(diào)用類當(dāng)中任何非常量型的成員函數(shù)(除了被編譯器隱式調(diào)用的構(gòu)造函數(shù)和析構(gòu)函數(shù))。看下面的代碼;    #include iostream.h    class Date    {    int month,day,year;    public:    Date(int m,d,y):month(m),day(d),year(y) {}    void display()    {    cout < }    }    int main()    {    const Date dt(4,7,2004);    dt.display(); //error    return 0;    }   這個(gè)程序盡管編譯時(shí)沒有問題,但運(yùn)行時(shí)卻出錯(cuò)了。這是因?yàn)槌A繉?duì)象不能調(diào)用非常量函數(shù)。編譯器只看函數(shù)的聲明,而不在乎函數(shù)的具體實(shí)現(xiàn)。實(shí)際上函數(shù)的實(shí)現(xiàn)可以在程序中的任何地方,也可以是在另一個(gè)源代碼文件中,這就超過了編譯器的當(dāng)前可見范圍。    //date.h    class Date    {    int month,day,year;    public:    Date(int m,d,y);    void display();    };    //date.cpp    #include iostream.h    #include date.h    Date::Date(int m,d,y):month(m),day(d),year(y) {}    void Date::display()    {    cout < }    //program.cpp    #include iostream.h    #include date.cpp    int main()    {    const Date dt(4,7,2004);    dt.display();    return 0;    }   解決出錯(cuò)的問題有兩個(gè)方法:第一是聲明display()函數(shù)為常量型的    //in date.h    void display() const    //int date.cpp    void Date::display() const    {    cout < }   另一個(gè)解決方式就是省略掉Date對(duì)象聲明里的const修飾符。    Date dt(4,7,2004);   還有另一個(gè)容易出錯(cuò)的地方:    void abc(const Date & dt)    {    dt.display(); //error 提示display沒有const修飾符    }   函數(shù)abc()聲明了一個(gè)Date對(duì)象的常量引用,這說明該函數(shù)不會(huì)修改傳遞進(jìn)來的參數(shù)的值。如果Date::display()函數(shù)不是常量型的,那么在函數(shù)abc()里就不能調(diào)用它,因?yàn)榫幾g器會(huì)認(rèn)為Date::display()函數(shù)有可能會(huì)修改常量的值。   不論類對(duì)象是否是常量型的,它必須修改某個(gè)數(shù)據(jù)成員的值時(shí),ANSI委員會(huì)設(shè)立了mutable關(guān)鍵字。
    五、可變的數(shù)據(jù)成員   假設(shè)需要統(tǒng)計(jì)某個(gè)對(duì)象出現(xiàn)的次數(shù),不管它是否是常量。那么類當(dāng)中就應(yīng)該有一個(gè)用來計(jì)數(shù)的整型數(shù)據(jù)成員。只要用mutable修飾符來聲明該數(shù)據(jù)成員,一個(gè)常量型的成員函數(shù)就可以修改它的值。    #include iostream.h    class AValue    {    int val;    mutable int rptct;    public:    AValue(int v) : val(v), rptct(0) { }    ~AValue()    {    cout < }    void report() const;    };    void AValue::report() const    {    rptct++;    cout << val << endl;    }    int main()    {    const AValue aval(123);    aval.report();    aval.report();    aval.report();    return 0;    }