天天看點

編寫類String的構造函數、析構函數和指派函數(2)

編寫類String的構造函數、析構函數和指派函數。重載輸出運算符。

class String
{ 
 public: 
     String(const char *str = NULL); // 普通構造函數 
     String(const String &other); // 拷貝構造函數 
     ~ String(void); // 析構函數 
     String & operator =(const String &other); // 指派函數 
 private: 
     char *m_data; // 用于儲存字元串 
};
           

當類中包括指針類成員變量時,一定要重載其拷貝構造函數、指派函數和析構函數。實作如下:

//普通拷貝函數
mystring::mystring(const char*str)
{
    if (str == nullptr)
    {
        m_data = new char[];
        if (m_data != nullptr)
            *m_data = '\0';
        else
            return;
    }
    else
    {
        int length = strlen(str);
        m_data = new char[length + ];
        if (m_data != nullptr)
            strcpy_s(m_data, (length+), str);
        else
            return;
    }
}   
//拷貝構造函數
mystring::mystring(const mystring &o)
{
    int length = strlen(o.m_data);
    m_data = new char[length + ];
    if (m_data != nullptr)
        strcpy_s(m_data, (length+), o.m_data);
    else
        return;
}
//析構函數。
//若不重載,在析構時指針作為内在類型自動銷毀,但實際記憶體不會。是以需要重新定義析構函數。
//一般地,重載析構函數意味着也需要一個拷貝構造函數和一個拷貝指派運算符。見《c++ primer》P447。
mystring::~mystring(void)
{
    delete[] m_data;
}
//拷貝指派運算符
mystring & mystring::operator=(const mystring &o)
{
    if (this == &o)
        return *this;

    delete [] m_data;
    int length = strlen(o.m_data);
    m_data = new char[length + ];
    if (m_data != nullptr)
    {
        strcpy_s(m_data, (length + ), o.m_data);
        return *this;
    }
}
           

重載輸出運算符

class mystring {
public:
    /*和上述相同*/
    friend ostream & operator<<(ostream &os, const mystring &ms);
    //ostream & operator<<(ostream &os);
    //上式等價于 ostream & operator<<(this, ostream &os);
    //如下形式提示參數過多;
    //ostream & operator<<(ostream &os, const mystring &ms);
    void print() { cout << this->m_data; }
private:
    char *m_data;
};
           

《c++ primer》P494曾讨論過重載輸出運算符。在這裡實作下。

1、當我在類的成員函數中加上:

ostream & operator<<(ostream &os, const mystring &ms);
           

提示參數過多。因為是成員函數,是以隐式地會在參數清單中加上this指針。

于是我改成:

ostream & operator<<(ostream &os);
//等價于 ostream & operator<<(this, ostream &os);
           

測試語句寫成:

正常輸出沒問題。但從字面直覺上這樣是不對的。

再看書方明白作者們的讨論很有道理的。應該把函數定義為普通的非成員函數。如下:

ostream & operator<<(ostream &os, const mystring &ms)
{
    os << ms.m_data;
    return os;
};
           

因為要通路私有成員,是以聲明為友元即可。

class mystring {
public:
    /*其餘相同*/
    friend ostream & operator<<(ostream &os, const mystring &ms);
}
           

再測試如下:

輸出正常,符合直覺。彼時還有點小疑惑。為什麼這樣寫就可以調用上述函數呢?形式不是很一緻啊。

cout << a;
ostream & operator << (ostream &os, const mystring &ms);
           

查閱P490發現:

對于二進制運算符來說,左側運算對象傳遞給第一個參數,右側運算符對象傳遞給第二個參數。

這就對了。當我們寫成:

實際調用形式為:

自然能夠和

ostream & operator<< (ostream &os, const mystring &ms);
           

所比對。OK。