C++快速入門——基礎知識筆記
1、this
this是個特殊指標,在class裡面指向當前物件,例如。
class Person
{
private:
char *name;
public:
void setName(char *name)
{
this->name = name;
}
};
2、::
- 用於指定當前函式屬於某個類,例如setAge函式屬於Person類的一個方法。
- 用於指定呼叫的函式是來自哪個名稱空間,例如呼叫的是名稱空間A裡面的PrintVersion函式。
void Person::setAge(int age) { this->age = age; } A::PrintVersion();
3、 using用法:
- using A::Person; 宣告使用名稱空間A裡面的Person類,不宣告的話在使用類之前要加名稱空間。
- using A::PrintVersion; 匯入名稱空間A裡面的PrintVersion函式,不宣告的話在呼叫函前面要加名稱空間。
- 直接using namespace A; 一次性匯入名稱空間A涉及的類和函式。
4、cout
需要包含標頭檔案iostream:#include ,不需要加.h,引用標準名稱空間std。cout使用方法:cout<<"age = “<<age<<”,name = "<<name<<endl;這裡的<<是過載了左移運算,達到字串拼接的效果,enld是回車換行。
cout有時候的輸出格式不是我們想要的,如下會輸出i = d,需要加強轉來解決。
uint8_t i = 100;
cout<<"i = "<<i<<endl;
5、建構函式
- 呼叫無參建構函式的方法:Person person;或者Person person(“zhangsan”,18);而Person person()只是宣告一個函式,並不是定義一個類變數。
- 建構函式需要public屬性。
- 指標方式定義類變數:Person *per = new Person;或者Person *per = new Person();這兩種方式都是可以的,都會呼叫無參的建構函式。刪除一個類:delete per。
- 建構函式傳入預設引數,如Person(int age,char *name = “zhangsan”)。
- 一旦定義了有參建構函式,則必須定義一個無參建構函式。
6、解構函式
解構函式使用者釋放一些類裡面動態分配的記憶體,函式定義格式為:類名(),例如Person(),解構函式無參。
7、類的預設函式
-
預設建構函式:一個無參的建構函式,函式的內容為空
-
預設的解構函式:函式的內容為空
-
預設的拷貝函式:是一個特殊的建構函式,其入參是該類的引用。當建立一個類的時候,如果傳入的引數是同一個類的引用,那麼會拷貝一份,注意傳入的引數是類引用,而不是指標。例如:
Person *per = new Person(25,"Dokin"); Person *per2 = new Person(*per); 或 Person per(25,"Dokin"); Person per2(per);
類的預設拷貝函式在使用上有風險,因為創建出的類物件,其成員如果是指標型別,會和類引用指向同一空間,在記憶體分配和釋放上就有可能產生被重複釋放的問題,這種情況下需要重寫拷貝函式。
8、建構函式呼叫順序
-
按執行中定義物件的順序呼叫建構函式,靜態物件只調用一次建構函式,全域性物件在main函式執行前被構造。
-
類定義中如果使用了別的類,那麼會先按編碼順序依次呼叫別的類的建構函式,然後再呼叫本類的建構函式。
-
類的建構函式需要構造別的類時,在建構函式後面加:號,多個類用,隔開。如下面例子所示。注意,構造順序和:後面的順序無關,只和定義類成員的順序有關,即下面的例子依然是father先被構造。析構的順序則和構造的順序剛好相反。
class Student { private: Person father; Person mother; int age; public: Student(){} Student(int age,char *father,int father_age,char *mother,int mother_age)\ :mother(mother,mother_age),father(father,father_age) { this->age = age; } }; int main(int argc,char **argv) { Student Dokin(15,"bill",40,"lily",39); return 0; }
9、類的靜態成員和方法
類裡面可以使用static對成員和方法進行修飾,表明該成員或方法屬於類,而不是屬於類的例項物件。
類的靜態成員即使是private許可權,也可以通過類名來直接訪問。
靜態方法只能訪問靜態變數,不能訪問非靜態變數,因為靜態變數屬於類,而非靜態變數屬於類的例項物件。
類的例項物件也可以訪問類的靜態方法。
類的靜態方法可以在類裡面宣告然後類的外面定義,例如:
class Person
{
private:
static int cnt;
public:
static int getCnt();
/* ... */
}
int Person::getCnt()
{
return Person::cnt;
}
類定義時並沒有分配記憶體空間,因此需要在外部進行定義和初始化,下面是一個例子。
class Person
{
private:
char *name;
int age;
static int cnt;
public:
Person()
{
cnt ++;
this->name = NULL;
}
~Person()
{
cnt --;
}
static int getCnt()
{
return cnt;
}
}
int Person::cnt = 0;
int main(int argc,char **argv)
{
Person per1;
Person per2;
cout<<"cnt = "<<Person::getCnt()<<endl;
}
10、友元函式
在類的定義中,可以用friend關鍵字來宣告一個友元函式,友元函式可以直接訪問所在類的私有成員,從而提高效率。下面是一個例子。
#include <iostream>
using namespace std;
class Point
{
private:
int x;
int y;
public:
Point(){}
Point(int x,int y):x(x),y(y){}
void print()
{
cout<<"x = "<<x<<",y = "<<y<<endl;
}
friend Point addPoint(Point &p1,Point &p2);
};
Point addPoint(Point &p1,Point &p2)
{
Point point;
point.x = p1.x + p2.x;
point.y = p1.y + p2.y;
return point;
}
int main(int argc,char **argv)
{
Point p1(1,2);
Point p2(3,4);
Point p3 = addPoint(p1,p2);
p3.print();
}
11、const成員函式
在成員函式後面加上const表示此函式沒有修改操作,如void printInfo(void)const。
12、運算子過載
例如過載++號運算,那麼函式名為Point operator++(Point p),通過入參的不同可以實現運算子的不同功能,例如以下++的實現。
/* 實現++p */
Point operator++(Point &p)
{
p.x += 1;
p.y += 1;
return p;
}
/* 實現p++ */
Point operator++(Point &p, int a)
{
Point temp;
temp = p;
p.x += 1;
p.y += 1;
return temp;
}
上述函式通過函式入參的不同實現了函式過載,實現了前++和後++。
注意Point operator++(Point &p)函式中定義了返回了一個臨時變數p,這會造成臨時變數p的建構函式和解構函式被呼叫,從而影響函式執行效率,最佳的實現方式如下,返回一個引用,這樣就不會有臨時變數,也就不會呼叫建構函式和析構函數了。
/* 實現++p */
Point& operator++(Point &p)
{
p.x += 1;
p.y += 1;
return p;
}
過載=號運算子可以解決值拷貝造成的問題:拷貝類的指標成員,導致兩個類的成員指向同一塊地址。過載=號可以在過載函式裡對指標成員進行記憶體申請和銷燬,避免指向同一地址。
以下操作的結果是不同的:p2 = p1會呼叫預設的拷貝函式,而不是呼叫operator=過載函式。先定義p3,然後p3=p1這樣才會呼叫operator=過載函式。
Person p1;
Person p2 = p1;
Person p3;
p3 = p1;