前面我們在定義類時多次使用到了 public 關鍵字,表示類的成員具有“公開”的訪問權限,這節我們就來詳細講解。
C++通過 public、protected、private 三個關鍵字來控制成員變量和成員函數的訪問權限,它們分別表示公有的、受保護的、私有的,被稱為成員訪問限定符。所謂訪問權限,就是你能不能使用該類中的成員。
Java、C# 程序員注意,C++ 中的 public、private、protected 只能修飾類的成員,不能修飾類,C++中的類沒有共有私有之分。
在類的內部(定義類的代碼內部),無論成員被聲明為 public、protected 還是 private,都是可以互相訪問的,沒有訪問權限的限制。
在類的外部(定義類的代碼之外),只能通過對象訪問成員,並且通過對象只能訪問 public 屬性的成員,不能訪問 private、protected 屬性的成員。
本節重點講解 public 和 private,protected 將在繼承中講解。
下面通過一個 Student 類來演示成員的訪問權限:
#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(){
//在棧上創建對象
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
類的聲明和成員函數的定義都是類定義的一部分,在實際開發中,我們通常將類的聲明放在頭文件中,而將成員函數的定義放在源文件中。
類中的成員變量 m_name、m_age 和m_ score 被設置成 private 屬性,在類的外部不能通過對象訪問。也就是說,私有成員變量和成員函數只能在類內部使用,在類外都是無效的。
成員函數 setname()、setage() 和 setscore() 被設置為 public 屬性,是公有的,可以通過對象訪問。
private 後面的成員都是私有的,直到有 public 出現才會變成共有的;public 之後再無其他限定符,所以 public 後面的成員都是共有的。
成員變量大都以
m_
開頭,這是約定成俗的寫法,不是語法規定的內容。以
m_
開頭既可以一眼看出這是成員變量,又可以和成員函數中的形參名字區分開。
以 setname() 為例,如果將成員變量
m_name
的名字修改為
name
,那麼 setname() 的形參就不能再叫
name
了,得換成諸如
name1
、
_name
這樣沒有明顯含義的名字,否則
name=name;
這樣的語句就是給形參
name
賦值,而不是給成員變量
name
賦值。
因為三個成員變量都是私有的,不能通過對象直接訪問,所以必須借助三個 public 屬性的成員函數來修改它們的值。下面的代碼是錯誤的:
Student stu;
//m_name、m_age、m_score 是私有成員變量,不能在類外部通過對象訪問
stu.m_name = "小明";
stu.m_age = 15;
stu.m_score = 92.5f;
stu.show();
簡單地談類的封裝
private 關鍵字的作用在於更好地隱藏類的內部實現,該向外暴露的接口(能通過對象訪問的成員)都聲明為 public,不希望外部知道、或者只在類內部使用的、或者對外部沒有影響的成員,都建議聲明為 private。
根據C++軟件設計規范,實際項目開發中的成員變量以及只在類內部使用的成員函數(只被成員函數調用的成員函數)都建議聲明為 private,而只將允許通過對象調用的成員函數聲明為 public。
另外還有一個關鍵字 protected,聲明為 protected 的成員在類外也不能通過對象訪問,但是在它的派生類內部可以訪問,這點我們將在後續章節中介紹,現在你只需要知道 protected 屬性的成員在類外無法訪問即可。
有讀者可能會提出疑問,將成員變量都聲明為 private,如何給它們賦值呢,又如何讀取它們的值呢?
我們可以額外添加兩個 public 屬性的成員函數,一個用來設置成員變量的值,一個用來修改成員變量的值。上面的代碼中,setname()、setage()、setscore() 函數就用來設置成員變量的值;如果希望獲取成員變量的值,可以再添加三個函數 getname()、getage()、getscore()。
給成員變量賦值的函數通常稱為 set 函數,它的名字通常以
set
開頭,後跟成員變量的名字;讀取成員變量的值的函數通常稱為 get 函數,它的名字通常以
get
開頭,後跟成員變量的名字。
除了 set 函數和 get 函數,在創建對象時還可以調用構造函數來初始化各個成員變量,我們將在《C++構造函數》一節中展開討論。不過構造函數只能給成員變量賦值一次,以後再修改還得借助 set 函數。
這種將成員變量聲明為 private、將部分成員函數聲明為 public 的做法體現了類的封裝性。所謂封裝,是指盡量隱藏類的內部實現,只向用戶提供有用的成員函數。
有讀者可能會說,額外添加 set 函數和 get 函數多麻煩,直接將成員變量設置為 public 多省事!確實,這樣做 99.9% 的情況下都不是一種錯誤,我也不認為這樣做有什麼不妥;但是,將成員變量設置為 private 是一種軟件設計規范,尤其是在大中型項目中,還是請大家盡量遵守這一原則。
為了減少代碼量,方便說明問題,本教程中的類可能會將成員變量設置為 public,請讀者不要認為這是一種錯誤。
對private和public的更多說明
聲明為 private 的成員和聲明為 public 的成員的次序任意,既可以先出現 private 部分,也可以先出現 public 部分。如果既不寫 private 也不寫 public,就默認為 private。
在一個類體中,private 和 public 可以分別出現多次。每個部分的有效范圍到出現另一個訪問限定符或類體結束時(最後一個右花括號)為止。但是為了使程序清晰,應該養成這樣的習慣,使每一種成員訪問限定符在類定義體中只出現一次。
下面的類聲明也是完全正確的:
class Student{
private:
char *m_name;
private:
int m_age;
float m_score;
public:
void setname(char *name);
void setage(int age);
public:
void setscore(float score);
void show();
};