1. 程式人生 > >c++基礎第二章(物件)

c++基礎第二章(物件)

前言,c++是面對物件的語言

任何一個物件都應當具有 屬性 和 行為 這兩個要素。一個物件一般是由一組屬性和一組行為構成的。

也就是說 在 c++ 中物件是由  資料(屬性)  和 函式(行為) 兩部分組成。函式是用來對資料進行操作,用來實現某種功能。

物件具有封裝性 和資訊隱蔽性可以對一個物件進行封裝處理,把它的一部分屬性和功能對外界進行遮蔽,也就是說從外界看不到,甚至不可知

  (1).例如  DVD 機裡有電路板和各種機械控制部件,但是外部是看不到的,我們只能從外面看到他只是一個“黑箱子”,表面有幾個按鈕,這就是DVD機對外界的介面,人們不逼你瞭解DVD機裡面的結構和工作原理,只需要直到按某一個鍵就能使DVD機執行相應的操作.

  優點:大大降低了人們操作對物件的複雜程度,使用物件的人完全不必知道物件內部的具體細節,只需要瞭解外部功能就可以了,就像傻瓜相機,你不必知道它是怎麼做到的,你只需要像傻瓜一樣會按按鈕就可以了。官方的說就是把物件的內部實現和外部行為分隔開來。

封裝性

(1)將有關資料和操作程式碼封裝在一個物件中,形成一個基本單位,各個物件互不干擾。

(2)將物件中某些部分對外部隱藏(隱藏內部細節),只留下少數介面(不然怎麼和外部聯絡,外部怎麼使用這個物件呢?),這樣做有利於資訊保安,防止無關的人瞭解和修改資料。

引出類

抽象:作用是表示同一類事物的本質。例如所有國籍為中國的人,可以抽象為“中國人”,凡是有輪子,能滾動前進的陸地交通工具,抽象為“車”。

而物件是具體存在的,例如一個三角形可以作為一個物件,10個尺寸不同的三角形是10個物件,這10個物件有相同的屬性和行為(因為他們只是具體的邊長不同而已),這時可以將這10個物件歸為一類。正如  10箇中國人屬於“中國人”類。

類是物件的抽象。物件是類的特例,或者說物件是類的具體表現形式。

一.1,類的宣告

class Student
{
	private:		//私有資料和成員函式 
	 int ID;
	 string name;
	 string sex; 
	public:			//公用的資料和成員函式 
	void display()
	{
		cout << "ID = " << ID << endl;
		cout << "name = " << name << endl;
		cout << "sex = " << sex << endl;
	}
} ;
Student stud1, stud2; //定義了Student 類的物件stud1和stud2 

在類內的定義中即不指定private,也不指定public,則系統預設為是私有的。

類的一般形式

class 類名 
{
	private:		
            //私有資料和成員函式 
	public:			 
	    //公用的資料和成員函式
} ;

private :被宣告為私有成員,只能被本類中的成員函式引用,類外不能呼叫(友元函式除外,第三章會講)

public :被宣告為公用的,既可以被本類的成員函式引用,還可以外界呼叫。

舉個栗子,這個類就相當與你的家,私有private就是臥室,public就是客廳,而臥室只允許自己的家人進,不允許外人進的。而客廳嘛就可以招待各種客人了。

在一個類中  private 和 public可以出現多次,但是為了使程式清晰:使每一個成員訪問限定符在類的定義體中只出現一次。

一.2,類的成員函式

簡稱類函式,用法與函式一樣,但是在因為類中:他是一個類的一個成員,所以他可以被指定為 private(私有的)  public(共有的)  protected(受保護的).

使用時要注意許可權(是否能被呼叫)以及它的作用域(函式能使用什麼範圍內中的資料和函式)例如私有成員函式只能被本類中的其他成員函式所呼叫,不能被類外呼叫,成員函式可以訪問本類中任何成員,可以引用在本作用域中有效的資料。

一般做法是將需要被外界呼叫的成員函式指定為public,他們是類對外的介面

但是有些函式並不是準備為外界呼叫的,你不想外界使用,只是能讓本類函式用,那就指定為private

在類外定義成員函式

#include<iostream>
using namespace std;

class Student 
{
	public:			//公用的資料和成員函式 
		void display()
	private:		//私有資料和成員函式 
		int ID;
	 	string name;
	 	string sex; 
} ;

void Student::display() 
{
	cout << "ID = " << ID << endl;
	cout << "name = " << name << endl;
	cout << "sex = " << sex << endl;
}

在 類內定義成員函式是不需要在函式名字前面加上類名,因為你在類內定義,這個函式就屬於這個類,但是為了整潔,我們一般把函式寫在外面。但是成員函式寫在外面就必須加上類名了,不然不知道這個函式是哪個類的成員函式

一般我們在類內宣告函式,在類外定義函式,這樣可以減少類的長度,使類體更清晰,便於閱讀,而且可以使類的介面和類的實現細節分開。從使用者角度看這個類就像一個黑匣子,看不到細節,只知道怎麼用。

內建成員函式。

字面意思  就是說  成員函式也可以內建  在類外寫成員函式時前面加上  inline 就可以了。(很雞助 沒什麼卵用,建議不要用,這種方法還必須把宣告成員函式 和定義成員函式寫到一個檔案內,不然編譯不過)

成員函式的的儲存方式。

用類定義物件時,系統會為每個物件分配儲存空間, 如果一個類包括了資料和函式,按理說是要分別為資料和函式程式碼分配儲存空間的,那一個類定義10個物件是否需要為每一個物件的資料和函式程式碼分配空間,並把他們封裝在一起呢?

事實並不是這樣的:同一類的不同物件中的資料成員的值一般是不相同的,而不同物件的函式的程式碼是相同的,不論呼叫哪一個物件的函式的程式碼,其實呼叫的都是相同的內容的程式碼。

顯然這樣做會節約大量空間。c++ 編譯系統也就是這樣做的,因此對於每個物件所佔用的儲存空間只是該物件的資料成員所佔用的儲存空間,而不包括函式程式碼所佔用的儲存空間。

#include<iostream>
using namespace std;
class Time
{
	public:
		int hour;
		int minute;
		int second;
		void set()
		{
			char a , b, c;
			cin >> a >> b >> c;
		}
}; 
int main ()
{
	Time time1;
	cout << sizeof(time1) << endl;
	return 0;
}

sizeof(Time)的答案是  12   3個int型  一個int 4個位元組 ,set()函式內的3個定義並沒有算在  Time 定義物件的空間內

雖然成員函式並沒有放在物件的儲存空間中,但是從邏輯角度成員函式是和資料一起封裝在一個物件中的,只允許本物件中的函式訪問同一物件中的私有資料。

一.3,物件成員的引用

(1)通過物件名和成員運算子訪問物件中的成員

stud1.num = 100;    //假設num已經定義為公用的整型資料成員 
num = 100;    //沒有指出是哪個物件

訪問的一般形式為

物件名.成員名

stud1.display();    //正確,呼叫stu1的公用成員函式
display();         //沒有指明哪個物件的display();這時這個就是個函式不是成員函式。

所以 在 類中至少有一個公用成員函式,作為對外的介面,否則就無法對物件進行任何操作

通過指向物件的指標訪問物件中的成員

#include<iostream>
using namespace std;
class Time
{
	public:		        //資料成員是公用的才能在外部訪問 
		int hour;
		int minute;
		int second;
}; 

int main ()
{
	Time t, *p;		//定義物件t和指標變數p 
	p = &t; 		//使p指向物件t 
	cout << p->hour;	//輸出p指向的物件中的成員hour 
	return 0;
}

通過物件引用訪問物件中的成員

Time t1;        
Time &t2 = t1;
cout << t2.hour;     //hour是public內的

 

寫個例題

找出一個整型陣列中的元素的最大值

#include<iostream>
using namespace std;
class Array_max
{
	public:
		void set_value();
		void max_value();
		void show_value();
	private:		        
		int array[10];
		int max;
}; 

void Array_max::set_value()
{
	int i;
	for(int i = 0; i < 10; i++)
	cin >> array[i]	;
	
}
void Array_max::max_value()
{
	int i ;
	max = array[0];
	for(int i = 1; i < 10; i++)
	if(max < array[i])
	max = array[i];
}
void Array_max::show_value()
{
	cout << "max = " << max << endl;
}
int main ()
{
	Array_max arrmax;
	arrmax.set_value();
	arrmax.max_value();
	arrmax.show_value();
	return 0;
}

下面長篇文章來襲

雖然很長 但是讀過之後對類還有成員函式的封裝  資訊的隱藏會有更深的理解

類的封裝性和資訊隱藏

公用介面與私有實現的分離

一般把所有的資料指定為私有,使他們與外界分離,把需要讓外界呼叫的成員函式指定為公用的。在類外雖然不能直接訪問私有資料成員,但是可以通過呼叫公有成員函式來引用甚至修改私有資料成員。因此外界與物件的唯一聯絡渠道就是呼叫公有成員函式,這樣可以使類Yui外界的聯絡降到最低。可以說公有成員函式是使用者使用類的公用介面,就是類的對外介面

就像照相機,人只需要知道按什麼按鍵能實現什麼功能就可以了,其中的原理不必瞭解那是設計師和廠家的事情。快門就是一個公用介面,使用者可以通過快門照相,但不能改變相機的結構和功能。一切與使用者無關的操作細節都被封裝在了相機內,使用者看不見,摸不到,改不了。這樣就實現了介面與現實分離

通過成員函式對資料成員進行操作稱為類的實的功能實現。為了防止使用者任意更改公用成員函式,改變對資料進行的操作,往往不讓使用者看到公用成員函式的原始碼,顯然更不能修改,使用者只能接觸到公用成員函式的目的碼。可以看到類中被操作的資料是私有的,類的功能的實現細節對使用者是隱蔽的,這種實現成為私有實現。這種“類的公用介面與私有實現的分離”形成了資訊的隱蔽。

使用者接觸到是公用的介面,而不能接觸到被隱蔽的資料和實現的具體細節。也就是說你只知道這個函式能實現什麼功能,而怎麼實現的並不知道。

類的宣告和成員函式定義的分離

一個類如果只被一個程式使用則只需要把這個類寫到這個程式的開始就可以了

但是如果是一個類被多個程式使用,這樣做的重複工作量就更大了,效率太低,這時就出現了把類的宣告(包含成員函式的宣告)放在指定的標頭檔案中,如果想用這個類,只需要把有關的標頭檔案包含進來即可,不必在程式中重複書寫。提高程式設計效率

為了實現資訊隱蔽,不讓使用者看到函式的執行細節,對類成員函式的定義一般不和類的宣告一起放在標頭檔案中,而放在另一個檔案中。包含成員函式定義的檔案就是類的實現(即通過呼叫成員函式用來實現類的功能)。特別注意:在系統提供的標頭檔案中只包括對成員函式的宣告,而不包括成員函式的定義。類宣告和函式的定義分別放在兩個檔案中。

實際上就是 (1)類宣告的標頭檔案(字尾為.h或無後綴)(2)類實現檔案(字尾為.cpp)包含類成員函式的定義;(3)類的使用的檔案(字尾為.cpp)主檔案

例子

檔案1

//student.h

#include<string>
using namespace std;
class Student
{
	public :
		void display();
	private :
		int num;
		string name;
		string sex;
}

檔案2

//student.cpp

#include<string>
#include<iostream>
#include"student.h"
using namespace std;
void Student::display()
{
	cout << "number =" << number << endl;
	cout << "name = " << name << endl;
	cout << "sex = " << sex << endl;
}

檔案3

//main.cpp

#include<string>
#include<iostream>
#include"student.h"
using namespace std;
int main ()
{
	Student stud1;
	stud1.display();
	return 0;
}

注意,由於標頭檔案student.h放在使用者當前目錄中,所以用   "student.h" 而不用 <student.h>

讀者可能會思考這樣一個問題,如果一個類宣告多次被不同的程式所選用,每次都要對包含成員函式定義的原始檔(例如上面的student.cpp)進行編譯,這是否可以改進呢?現實是可以的,的確不需要每次對它進行重複編譯,而只需要編譯一次就可以了。把student.cpp第一次編譯後所形成的目標檔案儲存起來,以後在需要時把它調出來直接與主檔案的目標檔案連結即可,這和使用庫函式類似。

這也是成員函式的定義不放在一個頭檔案的一個好處,如果對成員函式的定義也放在類的宣告的標頭檔案中,那麼不僅不能實現資訊的隱藏,而且在對使用這些類的每一個程式的每一次編譯時都要對成員函式進行編譯,即同一個成員函式的定義會多次被重複編譯。把成員函式的定義單獨放在另一個檔案中,單獨編譯,就可以做到不重複編譯。

在實際工作中,我們並不是把一個類的宣告做一個頭檔案,而是將若干個常用的功能相近的類的宣告集中在一起,形成類庫。

類庫有兩種:(1)c++編譯系統提供的標誌類庫 (2)使用者根據自己的需要做的使用者類庫,提供給自己或授權他人使用,稱為自定義類庫。

類庫包括兩部分:(1)類宣告標頭檔案;(2)已經過編譯的成員函式的定義,它是目標檔案。

使用者只需要把類庫裝到自己的計算機系統中,並在程式中用到#incldue指令將有關的類的宣告的標頭檔案包含到程式中,就可以在程式中使用這些類

類宣告標頭檔案就成為使用者使用類庫的有效方法和公用介面。

這就實現介面與現實的分離,為軟體開發商向用戶提供類庫創造了很好的條件,開發商把使用者所需要的各種類的宣告按類放在不同的標頭檔案中,同時對包含成員函式定義的原始檔進行編譯,得到成員函式定義的目的碼。軟體開發商只需要向用戶提供這些標頭檔案和類的實現的目的碼(不需要提供函式定義的原始碼).使用者使用庫類中的類時,也只需要將有關標頭檔案包含到自己的程式中,並在編譯後連結成員函式定義的目的碼即可。使用者可以看到標頭檔案中類的宣告和成員函式的原型宣告,但是看不到定義成員函式的原始碼,更無法修改成員函式的定義,開發商的權益就時得到了保護。