- C中的字元常量其實是未命名的字元數組(由編譯器在尾部插入Null 字元'/0'來標識串尾)
char hello[] = "hello"; valid
char hello[5];
hello = "hello"; invalid
初始化時,數組的長度必須大於等於字元常量的長度+1
char hello[5] = "hello"; invalid
char hello[6] = "hello"; valid
起源於20世紀初美國的一個叫墨非的倒黴蛋,大意是說一件事情只要有可能變糟,就一定會變糟。比如從餐桌上掉下的麵包片總是塗了果醬的一面掉地,電影院裡遲到的人總是坐在前排。
有些類很簡單,它們的結構就是它們的介面,所以不需要建構函式。
通常使用共有的資料成員不是什麼好事,因為類設計者無法控制何時訪問這些成員。
不是所有有建構函式的類都需要解構函式,例如:表示複數的類即使有建構函式也可能不需要解構函式。
有寫類需要虛解構函式只是為了聲明它們的解構函式是虛的,當然,決不會用作基類的類是不需要虛解構函式的。任何虛函數只在繼承的情況下才有用。但是,你寫了一個叫B的類,而別人從它派生了一個類D,那麼B何時需要一個虛解構函式?只要有人可能會對實際指向D類型對象的B*指標執行delete運算式,你就需要給B加上一個虛解構函式。即使B和D都沒有虛函數,這也是需要的。
struct B{
String S;
};
struct D: B{
String t;
};
int main()
{
B * bp = new D;
delete bp;
}
這裡,即使B沒有虛函數,實際上連成員函數也沒有,如果B有一個虛解構函式,那麼Delete會出錯,虛解構函式通常是空的。
如果一個類已經有了一個建構函式,而你想聲明該類的對象可以不必顯示的初始化它們,則必須顯示的寫一個無參的建構函式。
建構函式的用途就是用一種明確定義的狀態來設定對象。對象的狀態由對象的資料成員進行反映。因此每個建構函式都要負責為所有的資料成員設定經過明確定義的值。這種說法不總是正確,但卻可以激勵進行思考。
很多時候答案都是"不",但有時候答案是"是"。關鍵在於複製構造該類的對象是否相當於複製其資料成員和基類對象。如果並不項當,就需要複製建構函式。
如果你的類在建構函式內分配資源,則可能需要一個顯示的複製建構函式來管理資源。
如果不想使用者能夠複製類的對象,就聲明複製建構函式(可能還有賦值操作符)為私人的
如果需要複製建構函式,同理多半也需要一個賦值操作符
賦值總是用新值取代目標對象的舊值,如果目標對象和來源物件是同一對象。就可能在沒有實施賦值之前已經把原對象銷毀了,例如:
class String{
public:
String& operator*(const String &s);
private:
char *data;
}
不正確的實現:
String & String::opetator=(const String&s)
{
delete [] data;
data = new char[strlen(s.data) + 1];
strcpy(data, s.data);
return * this
}
正確的實現
String & String::opetator=(const String&s)
{
if(&s != this)
{
delete [] data;
data = new char[strlen(s.data) + 1];
strcpy(data, s.data);
}
return * this
}
另一種可行的方法:
String & String::opetator=(const String&s)
{
char *newdata = new char[strlen(s.data) + 1];
strcpy(newdata , s.data);
delete [] data;
data = newdata;
return * this
}
如果使用者想要建立你的類的有序集合,就必須提供關係操作符。
- 在賦值建構函式和賦值操作符的參數類型前加const了麼
綁定一個非const引用到一個臨時對象是非法的?
取回長度而不改變該值的函數應聲明為const;
template <class T> class Vector{
public:
int length() const;
}
否則我們會遇到下面的問題:
template<class T> int padded_length(const Vector<T>&v, int n)
{
int k = v.length(); //oops 該編譯通不過
return k>n ? k:n;
}