【C++】C++類的學習(一)——初識類
前言
C++在C語言的基礎上做了一些改進,使得C++具有了面向物件程式設計(Object Oriented Programming,OOP)的特性。其中最重要的改進就是提供了類的概念。可以說學習了C++卻不會使用類的話,那麼就沒有學習到C++的精髓。
在接下來的幾篇博文中,我將梳理一下自己學習C++中類的學習心得。類中涵蓋的知識點非常龐雜,我不會把每個細節都寫出來,我會沿著主線由淺入深來梳理,希望對看到這些博文且想了解類的你有所幫助。
初探類
類的基本思想是資料抽象和封裝。資料抽象是一種把介面和實現分離的程式設計技術。類的介面包括使用者所能夠執行的操作,類的實現包括類的資料成員、負責介面實現的函式體和各種私有函式。
封裝實現了類的介面和實現的分離。封裝隱藏了類的實現,封裝過後,使用者只能訪問類的介面,而不能訪問類的實現。
類是一種將抽象轉換為使用者定義型別的C++工具,它將資料表示和操縱資料的方法組合成一個整體。例如一個日常生活時間類,時間物件有兩個屬性,小時和分鐘,根據需要應該能夠對每個日常事務所花的時間進行操作和顯示。操作和顯示就需要類的介面函式。
一般的類由兩部分組成:
1. 類宣告:以資料成員的方式描述資料部分,以成員函式(被稱為方法)的方式描述介面函式。
2. 類方法定義:描述如何實現類成員函式。
簡單地說,類宣告給出了類的框架,而方法定義給出了類的細節。
私有成員與公有成員
在下面的程式碼中聲明瞭一個Time類;類中有兩個關鍵字private和public,它們描述了程式對類的成員的訪問控制。由於隱藏資料是OOP的主要目的之一,所以資料成員一般放在private部分,而介面函式則放在public部分。
#ifndef MYTIME_H #define MYTIME_H #include <iostream> using namespace std; class Time { //----------私有成員,類中的成員預設是私有的 private: int hours; int mintues; //----------共有成員 public: Time(); //預設建構函式 Time(int h, int m = 0); //顯式建構函式 Time(const Time &); //拷貝建構函式 ~Time(); //解構函式 void AddMin(int m); void AddHour(int h); void reset(int h = 0, int m = 0); //------展示函式show() //在const函式中不可呼叫非const函式成員 void Time::show() const { cout << "hours:" << hours << " " << "mintues:" << mintues << " "<<endl; } }; //-------時間重置,行內函數 inline void Time::reset(int h, int m) { hours = h; mintues = m; } #endif
使用類物件的程式可以直接訪問類的公有成員,但是不能直接訪問私有成員,要訪問私有成員則需要公有成員間接地訪問。例如在程式中定義一個Time類物件eating。可以通過eating訪問公有成員show()函式,而不能直接用eating訪問hours。
Time eating(1, 45);
eating.show(); //合法;
eating.hours; //非法,不能直接訪問私有成員。
注:類的成員預設是私有的,但是為了嚴謹一般還是用private關鍵字註明,而結構體的成員預設是公有的。
成員函式的實現
1. 在類外定義一個成員函式時,需要使用域解析運算子(::)來標識函式所屬的類。這意味著,不同的類中,可以定義同樣的成員函式而互不影響。
例如:
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}
2. 在宣告一個類時,可以將成員函式的定義直接放入類中,此時函式預設是一個行內函數,不需要新增域解析符。但是為了方便程式碼閱讀,一般不會將成員函式直接在類中實現。
在上面的程式碼中,成員函式show()就直接定義在了類的定義體中。
3. 也可以將函式的實現寫進類宣告的標頭檔案中,但是一定要新增inline關鍵字,在C++中的標頭檔案(.h)—詳解(2)中曾經提到過原因,如果不讓函式成為行內函數,當頭檔案被多個原始檔引用時,會出現重定義。(有疑惑的可以點選上面的連結進入閱讀博文)
上面程式碼中的,reset()函式就是採用行內函數的方式定義在了類定義的標頭檔案中。
類物件使用類成員
物件使用成員函式時使用成員運算子: .
例如:Time的一個物件eating呼叫show()函式。
eating.show();
類的const成員
為了保證資料的安全,在類的成員函式不修改物件的值時,應該儘量將成員函式定義為const成員函式。定義一個const類物件與定義一個const普通物件一樣,在物件前加上const 關鍵字。
定義一個的const成員函式時const關鍵字是放在括號後面的,他的意思是這個函式不不能修改呼叫它的物件的值。與返回值是否是常量無關。
void Time::show() const //const關鍵字被放在了函式名括號的後面
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " "<<endl;
}
一個const物件是無法呼叫非const成員函式的,以免非const成員函式修改const物件的資料,這無疑降低了程式出錯的可能性,而非const物件是可以呼叫const成員函式的。以下面的程式碼為例。
Time swiming(0, 45); //非const物件
const Time study(8, 5); //const物件只能呼叫const成員函式。
study.reset(0,0); //非法,const物件無法呼叫非const成員函式。
study.show(); //合法,show()是const成員函式。
swiming.show(); //合法;
當然了,在const函式中修改物件的值是非法的,編譯器無法通過。
成員初始化規則
- const修飾的變數定義後就不能更改了,因此,需要使用初始化列表來初始化。
- 引用在進行初始化後就不會再改變,因此,也需要使用初始化列表來初始化。
- 資料成員是物件時候,需要呼叫建構函式進行初始化(繼承時呼叫基類建構函式)
- static與類有關,不需要使用初始化列表。
- 指標的值在初始化後可以改變,即指向其它的儲存單元,因此,也不要使用初始化列表。
程式碼
為了方便大家的理解,在這裡貼出所有程式碼
//----mytime.h
#ifndef MYTIME_H
#define MYTIME_H
#include <iostream>
using namespace std;
class Time
{
//----------私有成員,類中的成員預設是私有的
private:
int hours;
int mintues;
//----------共有成員
public:
Time(); //預設建構函式
Time(int h, int m = 0); //顯式建構函式
Time(const Time &); //拷貝建構函式
~Time(); //解構函式
void AddMin(int m);
void AddHour(int h);
void reset(int h = 0, int m = 0);
//------展示函式show() //在const函式中不可呼叫非const函式成員
void Time::show() const //const關鍵字被放在了函式體的後面
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " "<<endl;
}
};
//-------時間重置,行內函數
inline void Time::reset(int h, int m)
{
hours = h;
mintues = m;
}
#endif
//--mytime.cpp
#include <iostream>
#include "mytime.h"
using namespace std;
//-------預設建構函式
Time::Time()
{
hours = mintues = 0;
cout << "呼叫預設建構函式" << endl;
}
//------顯式的建構函式
Time::Time(int h, int m) :hours(h), mintues(m)
{
cout << "呼叫顯式建構函式" << endl;
}
//------拷貝建構函式
Time::Time(const Time &t)
{
hours = t.hours;
mintues = t.mintues;
cout << "呼叫拷貝建構函式" << endl;
}
//------解構函式
Time::~Time()
{
cout << "呼叫了解構函式" << endl;
}
//-------小時相加
void Time::AddHour(int h)
{
hours += h;
}
//------分鐘相加
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}
//---test.cpp
#include <iostream>
#include "mytime.h"
using namespace std;
const void fun()
{
cout << 1 << endl;
}
int main()
{
Time eating(1, 45);
eating.show(); //合法;
//eating.hours; //非法,不能直接訪問私有成員。
Time swiming(0, 45); //非const物件
const Time study(8, 5); //const物件只能呼叫const成員函式。
//study.reset(0,0); //非法,const物件無法呼叫非const成員函式。
study.show(); //合法,show()是const成員函式。
swiming.show(); //合法;
system("pause");
return 0;
}
執行結果
結果分析
上面的結果和程式碼中都可以看到建構函式,解構函式以及拷貝建構函式,因為這三種函式是類非常重要的成員函式,因此下次進行單獨講解。
已完。。
參考書籍《C++ Primer 第五版》、《C++ Primer Plus 第六版》