C++筆試題 String類的實現 三大復制控制函數


這個在面試或筆試的時候常問到或考到。

已知類String的原型為:
class String
{
public:
     String(const char *str = NULL);// 普通構造函數
     String(const String &other);    // 拷貝構造函數
     ~ String(void);    // 析構函數
     String & operate =(const String &other);// 賦值函數
private:
     char *m_data;// 用於保存字符串
}; 
請編寫String的上述4個函數。
//普通構造函數
String::String(const char *str)
{
        if(str==NULL)
        {
                m_data = new char[1]; // 得分點:對空字符串自動申請存放結束標志'\0'的//加分點:對m_data加NULL 判斷
                *m_data = '\0';
        }    
        else
        {
         int length = strlen(str);
         m_data = new char[length+1]; // 若能加 NULL 判斷則更好
         strcpy(m_data, str);
        }
} 
// String的析構函數
String::~String(void)
{
        delete [] m_data; // 或delete m_data;
}
//拷貝構造函數
String::String(const String &other)    // 得分點:輸入參數為const型
{     
        int length = strlen(other.m_data);
        m_data = new char[length+1];     //加分點:對m_data加NULL 判斷
        strcpy(m_data, other.m_data);    
} 
//賦值函數
String & String::operate =(const String &other) // 得分點:輸入參數為const

型
{     
        if(this == &other)                    //得分點:檢查自賦值
                return *this;   
        delete [] m_data;                //得分點:釋放原有的內存資源
        int length = strlen( other.m_data );      
        m_data = new char[length+1];  //加分點:對m_data加NULL 判斷
        strcpy( m_data, other.m_data );   
        return *this;             //得分點:返回本對象的引用  

}

剖析:

能夠准確無誤地編寫出String類的構造函數、拷貝構造函數、賦值函數和析構函數的面試者至少已經具備了C++基本功的60%以上!
在這個類中包括了指針類成員變量m_data,當類中包括指針類成員變量時,一定要重載其拷貝構造函數、賦值函數和析構函數,
這既是對C++程序員的基本要求,也是《Effective C++》中特別強調的條款。
仔細學習這個類,特別注意加注釋的得分點和加分點的意義,這樣就具備了60%以上的C++基本功!
 
 

 

 

#include<iostream>
using namespace std;

class String
{
  friend ostream& operator<<(ostream& out,const String& str)  //輸出操作符重載
  {
   return str.Print(out);
  }
  public:
 String(const char *str = 0);// 普通構造函數
 String(const String &other); // 拷貝構造函數
 ~String(void) { delete [] data_; }// 析構函數
 String& operator=(const String &other);// 賦值函數
 char* data(void) const { return data_; }
  private:
 ostream& Print(ostream& out) const;
 char   *data_;    // 用於保存字符串
};

//賦值操作符首先要注意是不是自己賦給自己,如果是這樣的話什么也不做,把自己返回即可。

//其次就是別人賦值給自己,這時首先要自己把原來的值扔到,根據別人的大小開辟一塊空間

//准備盛放別人的內容,最后不要忘了返回對自己的引用。

String& String::operator =(const String& other)
{
 if(this!=&other)
 {
  delete [] data_;
  size_t length=strlen(other.data());
  data_=new char[length+1];
  strcpy_s(data_,length+1,other.data());
 }
 return *this;
}

//復制構造函數總是發生在構造階段,所以此時成員data_還沒有空間可以使用,應該先根據別

//人空間的大小開辟好空間,然后在把別人的內容拷貝進來。

String::String(const String &other)
{
 size_t length=strlen(other.data());
 data_=new char[length+1];
 strcpy_s(data_,length+1,other.data());
}

//由於輸出操作符通常寫成類的友元函數,這樣就可以寫類似cout<<s;如果不是這樣使用起來就會

//很奇怪,比如可能是s.print()之類,無法像cout<<s<<s1<<endl;那樣和標准庫完美結合,甚至如果

//你寫了一個ostream& operator<<(ostream& out,const String& str)忘了加上友元聲明,編譯器

//會認為你是重載了一元移位操作符<<,而且參數還加多了。

//輸出操作符的經典寫法就像本文這樣,另加一個Print成員函數來完成干活的功能讓<<來調用,之所

//以返回ostream& 也是和C++語言內建操作符機制保持一致,這樣就可以寫cout<<s<<s1<<endl;而不是

//cout<<s;cout<<s1;cout<<endl;

ostream& String::Print(ostream& out) const
{
 out<<data_;
 return out;
}

//此構造函數可以支持隱式類型轉換比如你可以這樣創建一個String對象 String s("Hello World !");此語句

//就是在調用這個構造函數,另外String s="Hello World !";會被解釋成String s=Sting("Hello World !");先

//根據字符數組構造一個臨時String對象(此對象在這條語句執行完之后就被析構),並緊接着調用String的賦值

//操作符重載函數

String::String(const char *str) // 6分
{
 if(str==NULL)                          
 {
  data_=new char[1];// 若能加 NULL 判斷則更好
  *data_='\0';                      
 }                                        
 else
 {
  size_t length = strlen(str);           
  data_ = new char[length+1]; // 若能加 NULL 判斷則更好      
  strcpy_s(data_,length+1, str);                
 }

void main()
{
 char* p="Hello World !";
 String s(p);
 cout<<s<<endl;
 String s1("How are you ?");
 cout<<s1<<endl;
 s1=s;
 cout<<s<<endl<<s1<<endl;
 s=s=s1;
 cout<<s<<endl<<s1<<endl;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM