C++高級編程----熟悉類和對象

     題目要求:設計一個電子表格,該電子表格有兩個類:Spreadsheet和SpreadsheetCell。每個Spreadsheet都包含了若干個SpreadsheetCell,此外SpreadsheetApplication類管理Spread集合。

step1 : 從最小單元SpreadsheetCell瞭解類和對象

1 編寫類定義和類方法

考慮實際電子表格允許存儲的對象可以是數字,可以是文本數據。如果接收文本數據,電子表格將轉換爲數字。簡單的

編程實現如下:

SpreadsheetCell.h 類方法定義

#SpreadsheetCell.h
#ifndef SPREADSHEETCELL_H_
#define SPREADSHEETCELL_H_
#include<string>
class SpreadsheetCell
{
    public:
        void setValue(double inDouble);
        void setString(const std::string& inString);
        const std::string& getString() const;
    private:
        double mValue;
        std::string mString;
        std::string doubleToString(double inDouble) const;
        double stringToDouble(const std::string& inString) const;
};
#endif

 SpreadsheetCell.cpp 類方法實現

#SpreadsheetCell.cpp
#include "SpreadsheetCell.h"
#include <iostream>
#include <sstream>

using namespace std;

void SpreadsheetCell::setValue(double inDouble){
    mString = inDouble;
}

void SpreadsheetCell::setString(const string& inString){
    mString = inString;
    mValue = stringToDouble(inString);
}

const string& SpreadsheetCell::getString() const{
    return mString;
}

string SpreadsheetCell::doubleToString(double inDouble) const{
    ostringstream ostr;
    ostr << inDouble;
    return ostr.str();    
}

double SpreadsheetCell::stringToDouble(const string& inString) const{
    double dValue;
    istringstream istr(inString);
    istr >> dValue;
    if(istr.fail() || !istr.eof()){
        return 0;
    }else{
        return dValue;
    }
}

2 編寫對象的創建和使用

    在堆棧中的對象調用.method(args): 

SpreadsheetCell mCell;
mCell.setValue(5.0);
cout << "mString " << mCell.getString() << endl;

    在堆中的對象調用->method(args)

SpreadsheetCell mCell = new SpreadsheetCell();
mCell -> setValue(5.0);
cout << "mStirng " << mCell -> getString() << endl;
delete mCell;
mCell = nullptr;

    二者的主要區別:在堆棧中創建的對象無需手動管理內容,創建的對象內存固定;在堆中創建的對象可以動態分配內存,但必須在創建時使用new表達式(首先通過operator new爲SpreadsheetCell對象分配內存,然後爲這個對象調用構造函數,此處構造函數使用默認構造函數),在銷燬時使用delete表達式(首先調用SpreadsheetCell對象的析構函數,然後調用operator delete釋放內存)。 

    在堆中使用對象時,爲避免發生內存錯誤,強烈推薦使用智能指針。

auto mCell = make_unique<SpreadsheetCell>();
mCell -> setValue(5.0)
cout << "mString " << mCell -> getString() << endl;

3 對象的生命週期:創建、銷燬、賦值

    1 編寫構造函數

//note the var defination order
SpreadsheetCell::SpreadsheetCell(double inDouble):mValue(inDouble), mString(doubleToString(inDouble)){
}

SpreadsheetCell::SpreadsheetCell(double inDouble){
    setValue(inDouble);
}

SpreadsheetCell::SpreadsheetCell(const std::string& inString){
    setString(inString);
}

在堆棧中調用構造函數:

SpreadsheetCell mCell(5.0);

在堆中調用構造函數:

SpreadsheetCell *mCell = new SpreadsheetCell(5.0);
delete mCell;
mCell = nullptr;
//more efficient way
auto smartmCell = make_unipue<SpreadsheetCell>(5.0);

    注:無論是在堆中還是在類的對象中聲明指針,但沒有立即初始化對象,都應將指針初始化爲nullptr,如果不賦初值nullptr,此時指針未定義,進而可能導致無法預料或難以診斷的內存錯誤。

    2 特殊的構造函數——複製構造函數

SpreadsheetCell::SpreadsheetCell(const SpreadsheetCell& src){
    mValue = src.mValue;
    mString = src.mString;
}

    複製構造函數允許所創建的對象是另一個對象的精確副本。如果沒有編寫複製構造函數,c++會自動生成一個,用源對象相應數據成員的值初始化新對象的每個數據成員,如果數據成員是對象,意味着調用複製構造函數。

    :c++傳遞函數參數的默認方式是按值傳遞,這意味着函數或者方法接收某個值或者對象的副本。因此,無論什麼時候給函數或者方法傳遞一個對象時,編譯器都會調用新對象的複製構造函數進行初始化。當函數或者方法返回對象時,也會調用複製構造函數,在此情況下,編譯器使用複製構造函數創建一個臨時的、沒有名稱的對象。可將傳遞的參數作爲const引用,從而避免複製構造函數的開銷。按引用傳遞只需要複製對象的地址,不需要複製對象的全部內容,因此比按值傳遞的效率更高,當按引用傳遞某個對象時,使用對象引用的函數或方法可以修改原始對象,如果只是爲了提高效率才使用按引用傳遞,可將對象設置爲const以排除這種可能。

    3 默認析構函數

    當銷燬對象時,首先調用析構函數,然後釋放對象佔用的內存。在析構函數中可以執行對象的清理,如釋放動態內存或關閉句柄文件。當堆棧中的對象超出作用域時,意味着當前的函數,方法或者代碼塊結束,對象被銷燬。沒有智能指針的幫助,在堆中分配的內存不會自動銷燬,必須使用delete刪除對象指針,從而調用析構函數,並釋放內存。

practice makes perfect!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章