C++學習筆記 (二) ---- 類和物件
①、類和物件
類的定義,如下:
class Student{
public:
//成員變數
char *name;
int age;
float score;
//成員函式
void say(){
cout<<name<<"的年齡是"<<age<<",成績是"<<score<<endl;
}
};
定義一個 Student 類,類名首字母一般大寫,{ } 內部包含成員變數和成員函式,類定義結束後有一個 ;
Student LiHua;//建立物件:
Student allStu[50];//建立物件陣列:
int a;int a[100];//有點類似於定義一個變數:
//物件指標:
Student stu;
Student *pStu = &stu;
Student *pStu = new Student;//在堆上建立物件:
注:在棧上建立物件是有名字的,如 stu;但是在堆上建立物件只是得到一個指標 pStu;只能通過指標訪問成員變數。
棧記憶體是程式自動管理的,不能使用 delete 刪除棧上的物件,堆記憶體是由程式設計師管理,可以使用 delete
物件建立完成後和結構體類似,棧物件可以通過點號 . 訪問成員變數。物件指標可以通過箭頭 -> 訪問類成員。
類成員函式定義在類體裡,預設是行內函數 inline ,一般我們不希望過多使用行內函數,所以是將函式宣告在類體,而將成員函式定義在類外,然後加上域解析符 :: ,代表函式屬於當前類。例:
class Student{ public: //成員變數 char *name; int age; float score; //成員函式 void say(); //函式宣告 }; //函式定義 void Student::say(){ cout<<name<<"的年齡是"<<age<<",成績是"<<score<<endl; }
②、類成員訪問許可權
C++ 通過 public、private、protected 三個關鍵字來控制成員變數和成員函式的訪問許可權,他們分別代表公有、私有、受保護的。在類的內部,所有成員都可以互相訪問。在類的外部,只能通過物件訪問 public 成員。例:
#include <iostream>
using namespace std;
//類的宣告
class Student{
private: //私有的
char *m_name;
int m_age;
float m_score;
public: //共有的
void setname(char *name);
void setage(int age);
void setscore(float score);
void show();
};
//成員函式的定義
void Student::setname(char *name){
m_name = name;
}
void Student::setage(int age){
m_age = age;
}
void Student::setscore(float score){
m_score = score;
}
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
int main(void)
{
//在棧上建立物件
Student stu;
stu.setname("小明");
stu.setage(15);
stu.setscore(92.5f);
stu.show();
//在堆上建立物件
Student *pstu = new Student;
pstu -> setname("李華");
pstu -> setage(16);
pstu -> setscore(96);
pstu -> show();
return 0;
}
//執行結果:
小明的年齡是15,成績是92.5
李華的年齡是16,成績是96
本例是通過 public 的成員函式去訪問 private 的成員變數,不能通過物件直接訪問 private 成員。
注:通常是將類的宣告放在標頭檔案中,而將成員函式的定義放在原始檔中。
物件的大小隻是和成員變數有關,和成員函式沒有關係,成員函式在程式碼區分配記憶體,而不是在堆疊區。
③、建構函式
函式名和類名相同,沒有返回值,使用者不能呼叫,而是在建立物件時自動執行。例:
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
//宣告建構函式
Student(char *name, int age, float score);
//宣告普通成員函式
void show();
};
//定義建構函式
Student::Student(char *name, int age, float score){
m_name = name;
m_age = age;
m_score = score;
}
//定義普通成員函式
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
int main()
{
//建立物件時向建構函式傳參
Student stu("小明", 15, 92.5f);
stu.show();
//建立物件時向建構函式傳參
Student *pstu = new Student("李華", 16, 96);
pstu -> show();
return 0;
}
建構函式主要是做一些初始化的工作,像是在建立物件時給成員變數賦值,建構函式必須是 public 屬性,否則無法呼叫。另外一旦定義了建構函式,在建立物件的時候必須呼叫,例如在上一個例子中,建立物件要是寫成 Student stu 就是錯誤的。
其次,建構函式也可以過載,和普通函式過載是一樣的。
④、建構函式的引數初始化表:可以在建構函式的函式體中對成員變數賦值。
例:
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
//採用引數初始化表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score)
{
//TODO:
}
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
int main(void){
Student stu("小明", 15, 92.5f);
stu.show();
Student *pstu = new Student("李華", 16, 96);
pstu -> show();
return 0;
}
定義建構函式時並沒有在函式體中對成員變數逐一賦值,其函式體為空(當然也可以有其他語句),而是在函式首部與函式體之間添加了一個冒號 :,後面緊跟 m_name(name), m_age(age), m_score(score) 語句,這個語句的意思相當於函式體內部的m_name = name; m_age = age; m_score = score; 語句,也是賦值的意思。
解構函式是銷燬物件時系統自動執行的一個進行清理工作的特殊函式 (釋放記憶體、關閉開啟的檔案等),函式名稱是類名前加一個 ~ 符號,並且沒有引數,沒有返回值,不能過載,所以一個類只有一個解構函式。如果使用者沒有定義,編譯器會自動生成一個預設的解構函式。
⑤、this 指標是一個 const 指標,它指向當前物件,this 只能在類的內部使用,通過它可以訪問當前物件的所有成員。注意:this 指標不能在 static 成員函式中使用。this 指標其實和建立物件時返回的指標是一樣的,只不過不能人為地給 this 指標賦值。例:
//給 Student 類新增一個成員函式 printThis();,用來檢視 this 指標的值
void Student::printThis(){
cout<<this<<endl;
}
//在 main() 函式中新增程式碼如下:
Student *pstu1 = new Student;
pstu1 -> printThis();
cout<<pstu1<<endl;
Student *pstu2 = new Student;
pstu2 -> printThis();
cout<<pstu2<<endl;
//執行結果:
0x7b17d8
0x7b17d8
0x7b17f0
0x7b17f0
⑥、static 成員變數是一種特殊的成員變數,它屬於類,而不屬於某個具體的物件,可作為多個物件的共享變數。
//static 成員變數必須在類宣告的外部進行初始化,具體形式是:
type class::name = value;
type 是變數的型別,class 是類名,name 是變數名,value 是初始值。
static 變數既可以通過物件來訪問,也可以通過類來訪問,但是要注意訪問許可權。
static 成員變數和普通 static 變數一樣,都在記憶體分割槽中的全域性資料區分配記憶體,不佔用物件的大小,到程式結束時才釋放。
static 成員函式只能訪問靜態成員 (包括變數和函式)。
⑦、const 成員變數:
對於 const 成員變數,只能使用引數初始化表的方式賦值
如下面這種寫法是錯誤的:
class Con{
private:
const int m_len;
int *m_arr;
public:
Con(int len);
};
Con::Con(int len){
m_len = len; //錯誤;
m_arr = new int[len];
}
const 成員函式可以使用類中的所有成員變數,但是不能修改,const 成員函式必須在宣告和定義的時候,都要在函式頭部的結尾處加上 const 關鍵字。
const 物件,一旦物件被定義為 const 後,就只能呼叫類的 const 成員了(包括變數和函式)例:
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
public:
void show();
char *getname() const;
int getage() const;
float getscore() const;
private:
char *m_name;
int m_age;
float m_score;
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
int main()
{
const Student stu("小明", 15, 90.6);
//stu.show(); //error
cout<<stu.getname()<<"的年齡是"<<stu.getage()<<",成績是"<<stu.getscore()<<endl;
const Student *pstu = new Student("李磊", 16, 80.5);
//pstu -> show(); //error
cout<<pstu->getname()<<"的年齡是"<<pstu->getage()<<",成績是"<<pstu->getscore()<<endl;
return 0;
}
getname()、getage()、getscore() 函式僅僅是獲得變數的值,所以加了 const 限制,這是一種保險的做法。
⑧、友元函式 friend
可以藉助友元函式來訪問其他類中的私有成員。友元函式可以是其他類的成員函式,也可以是非成員函式。
public:
friend void show(Student *pstu); //在類中將 show() 宣告為友元函式
//非成員函式
void show(Student *pstu){
//函式體;
}
//將Student類中的成員函式 show()宣告為友元函式
public:
friend void Student::show(Address *addr)
void Student::show(Address *addr){
//函式體;
}
//另外還可以將一個類宣告為另一個類的友元類,友元類中的所有函式都是另一個類的友元函式。
//在類中將Student類宣告為友元類
public:
friend class Student;
注:友元類是單向且不能傳遞的,B 是 A 的友元類,不代表 A 是 B 的友元類;
B 是 A 的友元類,C 是 B 的友元類,不等於 C 是 A 的友元類。
⑨、C++中的 struct 和 class 基本是通用的,都可以包含成員變數和成員函式,只是 class 的成員預設都是 private 屬性的,而 struct 的成員預設是 public 屬性。在繼承上也是一樣的許可權關係,但是 class 可以使用模板,但是 struct 不能。