1. 程式人生 > >C++程式設計-類與物件

C++程式設計-類與物件

面向物件的程式設計方法,能夠較好結構化設計方法中遇到的問題。
面向物件的程式 = 類 + 類 + …+ 類

1、面向物件的程式設計方法:

  • 將某類客觀事物共同特點(屬性)歸納出來,形成一個資料結構(可以用多個變數描述事物的屬性);
  • 將這類事物所能進行的行為也歸納出來,形成一個個函式,這些函式可以用來操作資料結構(這一步叫“抽象”)。
  • 然後,通過某種語法形式,將資料結構和操作該資料結構的函式“捆綁”在一起,形成一個“類”,從而使得資料結構和操作該資料結構的演算法呈現出顯而易見的緊密關係,這就是“封裝”
  • 面向物件的程式設計具有:
    -“抽象”
    -“封裝”
    -“繼承”
    -“多型”

    四個基本特點。

面向物件的程式設計模式:
程式設計模式圖
2、舉例:
將長、寬變數和設定長,寬,求面積,以及求周長的三個函式“封裝”在一起,就能形成一個“矩形類”。

長、寬變數成為該“矩形類”的**“成員變數”,三個函式成為該類的“成員函式”** 。 成員變數和成員函式統稱為類的成員。

class CRectangle {
 public: 
 	int w, h;
 	int Area() { 
 			return w * h;
 	 }
 	 int Perimeter(){ 
 	 		return 2 * ( w + h); 
 	 } 
 	 void Init( int w_,int h_ ) {
 	 		 w = w_; h = h_; 
 	 		 } 
 }; //必須有分號

int main( ) 
{ 
		int w,h; 
		CRectangle r; //r是一個物件 
		cin >> w >> h; 
		r.Init( w,h); 
		cout << r.Area() << endl << r.Perimeter(); 		
		return 0; 
}

通過類,可以定義變數。類定義出來的變數,也稱為類的例項,就是我們所說的**“物件”** 。
類的名字就是使用者自定義的型別的名字。可以象使用基本型別那樣來使用它。

和結構變數一樣,物件所佔用的記憶體空間的大小,等於所有成員變數的大小之和

每個物件各有自己的儲存空間。一個物件的某個成員變數被改變了,不會影響到另一個物件。

和結構變數一樣,物件之間可以用 “=”進行賦值,但是不能用 “==”,“!=”,“>”,“<”“>=”“<=”進行比較,除非這些運算子經過了“過載”。

3、用法

  • [1] 用法1:物件名.成員名
		CRectangle r1,r2; 
		r1.w = 5; 
		r2.Init(5,4);

Init函式作用在 r2 上,即Init函式執行期間訪問的 w 和 h是屬於 r2 這個物件的, 執行r2.Init 不會影響到 r1。

  • [2 ] 用法2:指標->成員名
	CRectangle r1,r2; 
	CRectangle * p1 = & r1; 
	CRectangle * p2 = & r2; 
	p1->w = 5; 
	p2->Init(5,4); //Init作用在p2指向的物件上
  • [ 3] 用法3:引用名.成員名
	CRectangle r2;
	CRectangle & rr = r2;
	rr.w = 5;
	rr.Init(5,4); //rr的值變了,r2的值也變
	
	void PrintRectangle(CRectangle & r)
	{ 
		cout << r.Area() << ","<< r.Perimeter(); 
	}
	CRectangle r3;
	r3.Init(5,4);
	PrintRectangle(r3);

4、類成員的可訪問範圍

在類的定義中,用下列訪問範圍關鍵字來說明類成員可被訪問的範圍:

–private: 私有成員,只能在成員函式內訪問
–public : 公有成員,可以在任何地方訪問
–protected: 保護成員。

如過某個成員前面沒有上述關鍵字,則預設地被認為是私有成員。
類成員的可訪問範圍

	class Man {
		int nAge; //私有成員
		char szName[20]; // 私有成員
	public:
		void SetName(char * szName){
			strcpy( Man::szName,szName);
		}
	};
  • 類的成員函式內部,能夠訪問:
    –當前物件的全部屬性、函式;
    –同類其它物件的全部屬性、函式。
  • 類的成員函式以外的地方只能夠訪問該類物件的公有成員
	class CEmployee {
		private: 
			char szName[30]; //名字 
		public : 
			int salary; //工資 
			void setName(char * name); 
			void getName(char * name); 
			void averageSalary(CEmployee e1,CEmployee e2); 
	}; 
	void CEmployee::setName( char * name) { 
			strcpy( szName, name); //ok 
	} 
	void CEmployee::getName( char * name) { 
			strcpy( name,szName); //ok 
	}
	void CEmployee::averageSalary(CEmployee e1, CEmployee e2){
	 	cout << e1.szName; //ok,訪問同類其他物件私有成員 
		 salary = (e1.salary + e2.salary )/2; 
	 } 
	 int main() 
	 { 
		CEmployee e; 		
		strcpy(e.szName,"Tom1234567889"); //編譯錯,不能訪問私有成員 
	 	e.setName( "Tom"); // ok 
	 	e.salary = 5000; //ok 
	 	return 0; 
	 }

5、建構函式 (constructor)

成員函式的一種

  • 名字與類名相同,可以有引數,不能有返回值(void也不行)
  • 作用是對物件進行初始化,如給成員變數賦初值
  • 如果定義類時沒寫建構函式,則編譯器生成一個預設的無引數的建構函式
  • 預設建構函式無引數,不做任何操作
  • 如果定義了建構函式,則編譯器不生成預設的無引數的建構函式
  • 物件生成時建構函式自動被呼叫。物件一旦生成,就再也不能在其上執行建構函式
  • 一個類可以有多個建構函式
class Complex { 
			private : 
				double real, imag; 
			public: 
				void Set( double r, double i); 
}; //編譯器自動生成預設建構函式 
Complex c1; //預設建構函式被呼叫 
Complex * pc = new Complex; //預設建構函式被呼叫

6、複製建構函式 copy constructor

  • 只有一個引數,即對同類物件的引用。
  • 形如 X::X( X& )或X::X(const X &), 二者選一 後者能以常量物件作為引數
  • 如果沒有定義複製建構函式,那麼編譯器生成預設複製建構函式。預設的複製建構函式完成複製功能
class Complex { 
		private : 
			double real,imag; 
}; 
Complex c1; //呼叫預設無參建構函式 
Complex c2(c1);//呼叫預設的複製建構函式,將 c2 初始化成和c1一樣

如果定義的自己的複製建構函式, 則預設的複製建構函式不存在。

class Complex { 
		public : 
			double real,imag; 
		Complex(){ } 
		Complex( const Complex & c ) { 
			real = c.real; 
			imag = c.imag; 
			cout << “Copy Constructor called”; 
		} 
}; 
Complex c1; 
Complex c2(c1);

複製建構函式起作用的三種情況

  1. 當用一個物件去初始化同類的另一個物件時。
Complex c2(c1);
Complex c2 = c1; //初始化語句,非賦值語句
  1. 如果某函式有一個引數是類 A 的物件, 那麼該函式被呼叫時,類A的複製建構函式將被呼叫。
void Func(A a1){ }
 int main()
 { 
 		A a2; 
 		Func(a2); 
 		return 0;
 }
  1. 如果函式的返回值是類A的物件時,則函式返回時, A的複製建構函式被呼叫:
class A 
{ 
	public: int v; 
	A(int n) { v = n; }; 
	A( const A & a) { 
		v = a.v; 
		cout << "Copy constructor called" <<endl; 
	} 
};