來自Stanley B.Lippman的《Essential C++》第四章重要內容的總結,第四章目錄:
1、實現Class
Class聲明
只有前置聲明之後 纔能有類指針的定義 或者 以此Class作爲數據類型
calss Stack; //聲明
...
Stack *pt = 0; //定義一個類指針
void pocess(const Stack&); //以Stack作爲數據類型
Class定義
所有member function都必須在Class主體內進行聲明,至於是否要同時進行定義,可以自由定義。如果定義在Class以外,用": :" 表示xx函數是xx類的一個member
2、 構造函數(constructor)和折構函數(destructor)
構造函數是用來初始化 date member的函數,constructor的函數名稱必須與Class名稱相同,沒有返回值,可以被重載。
定義方法一:
class Triangular {
public:
Triangular(); //default constructors
Triangular(int len);
Triangular(int len, int beg_pos);
};
如果構造函數沒有任何參數,有兩種可能:
1、它不接受任何參數,有可能有參數但是參數在這個構造函數內已經被寫死,不允許更改
2、爲每個參數提供了默認值,這種有默認值的構造函數也可以作爲default 構造函數
定義方法二:
成員初始化列表,欲賦值給member的數值被放在member名稱後面的小括號中。
Trianglular::Triangular(int len, int bp):_name("Triangular")
{
_length = len > 0 ? len : 1;
_beg_pos = bp > 0 ? bp : 1;
_next = _beg_pos - 1;
}
折構函數 與構造函數相對,一旦某個class提供有destructor,當其object結束生命時,便會自動調用destructor處理善後。主要用來釋放在constructor中或者對象生命週期中分配的資源。
3、mutable和const
對於const參數,編譯器必須保證參數在程序運行過程中不會被修改。
凡是在class主體以外定義的,如果是一個const member function,那就必須同時在聲明與定義中指定const。
class Triangular{
public:
int elem(int pos) const; //聲明
...
};
int elem(int pos) const{
return _elem[pos-1]; //定義時也要指定const
}
mutable
如果_next被表示爲mutable,那麼可以宣稱,對_next所做的改變不會破壞class object的常量性。
4、this指針
this指針在member function內用來指向其調用者,它可以讓我們訪問調用者的一切,下面提供copy函數的定義及調用。
Triangular& Triangular::copy(const Triangular &rhs) {
_length = rhs._length;
_begin_pos = rhs._begin_pos;
return *this;
}
tr1.copy(tr2); //調用,將tr2複製給tr1
5、靜態類成員
靜態成員數 static date member
靜態成員數用來表示唯一的、可共享的member。它可以在同一類的所有對象中被訪問。static date member在定義的時候它的名稱必須附上class scope運算符。
class Triangular{
public:
//...
private:
static vector<int>_elems; //static data member聲明
};
//以下代碼放在程序代碼文件中,例如Triangular.cpp
vector<int>Triangular::_elems; //絕對不能丟,否則無法被編譯器實現
靜態成員函數
一般情形下,member function必須通過其類的某個對象來調用,但是對於靜態成員函數可以直接調用,前提是利用class scope說明基於的類對象,且靜態成員函數沒有訪問任何的non-static member。
Triangular tri; //定義一個Triangular對象,名字是tri
bool is_elem = tri.is_elem(ival); //調用function member
bool is_elem = Triangular::is_elem(ival); //如果is_elem是靜態成員函數,可以直接調用
static bool is_elem(int); //在class內的函數聲明
6、運算符重載
像定義member function那樣來定義運算符,唯一的差別是它不用指定名稱,只需要在運算符前加上關鍵字operator即可。
class Triangular_iterator{
public:
bool operator==(const Triangular_iterator&) const; //運算符重載聲明
...
};
inline bool operator==(const Triangular_iterator &rhs) const{
return _index==rhs._inedx; //定義
}
if(trian1 == trian2)... //調用
運算符重載規則:
1、不能引入新的運算符;2、運算符函數列表中,必須至少有一個參數爲Class類型;3、優先級不可改變
7、訪問類的私有成員
任何類都可以將其他function或class指定friend,friend具備與class member function相同的訪問權限,可以訪問class 的私有成員。只需要在某個函數的原型上加上關鍵字friend,就可以將它聲明爲某個class的friend。
爲了讓定義成功通過編譯,必須在聲明之前,提供類的定義(使用的那個類),否則無法確定函數原型是否正確。
也可以把整個類作爲另一個類的friend
class Triangular{
friend class Triangular_iterator;
...
};
如果能通過public member function來訪問私有成員,那麼就不必通過建立friend 關係。
8、function object
function object是一種提供有function call運算符“()”的class
bool operator()(int value) const; //聲明
bool Lessthan::operator()(int value) const //定義
{
return value < _val;
}
for (int i = 0; i < vec.size(); i++) //調用
{
if (lt(vec[i]))
count++;
}
通常會把function object當作參數傳給泛型算法
vector<int>::const_iterator iter = vec.begin();
vector<int>::const_iterator it_end = vec.end();
os << "elements less than" << lt.comp_val() << endl;
while ((iter = find_if(iter, it_end, lt)) != it_end) //把function object當作參數傳給泛型算法
{
os << *iter << ' ';
++iter;
}
遇到的問題及總結
1、記錄程序運行的時間(秒及毫秒)
//程序運行時間(秒)
#include<ctime>
clock_t startTime, endTime;
startTime = clock(); //計時開始
...
endTime = clock(); //計時結束
cout << "time: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
//程序運行時間(毫秒)
#include<ctime>
DWORD startTime = GetTickCount();//計時開始
....
DWORD endTime = GetTickCount();//計時結束
cout << "The run time is:" << endTime - startTime << "ms" << endl;
2、註釋要規範,美觀,體現結構
https://blog.csdn.net/weixin_42488570/article/details/80760849
兩張註釋對比
一)基本沒有註釋
二)結構清晰,明白易懂
3、 錯誤LNK2001無法解析的外部符號
參考這篇文章:https://blog.csdn.net/aaron121211/article/details/50384289
處理函數有可能沒有被實現,成員數也有可能沒有被實現,比如static vector<int> _elems,除了在class內的申明,還要在cpp文件內定義(實現)!