1. 程式人生 > >C++學習筆記(6)

C++學習筆記(6)

面向物件程式設計: 1.物件和類

(1)宣告類: 類定義了物件的屬性行為

        一個物件的狀態: 用資料域以及他們的當前值來表示。

        一個物件的行為,由一組函式確定。

        所以在c++類中,用變數定義資料域,用函式來定義行為

 (2)定義類和建立物件:        定義一個圓的類:

#include <iostream>

using namespace std;

class Circle
{
	public:
	double radius;
	
	// constructor 
	Circle()
	{
		radius = 1.0;
	}
	// 構造方法 
	Circle(double new_radius)
	{
		radius = new_radius;
	}
	// 函式 
	double getArea()
	{
		return 3.14 * radius * radius;
	}
	
};     // 這裡要寫分號 

int main(int argc, char *argv[])
{
        Circle circle1;
	Circle circle2(12.5);
	Circle circle3(123);
	
	cout << "radius of circle 1 is " << circle1.radius << endl;
	cout << "Area of circle 3 is " << circle3.getArea() << endl;
   
	return 0;
}

public關鍵字:表示所有的資料域,建構函式和普通成員函式都可以通過類物件來訪問。如果不用關鍵字public,那麼這些成員的可見性預設為private

瞭解UML圖(Unified Modelling Language)統一建模語言描述

簡單程式:定義一個電視TV的類,包括頻道切換,開關機,音量調節

#include <iostream>

using namespace std;

class TV
{
    public:
    int channel;
    int volume_level;
    bool on;
    
    //定義構造方法 
    TV()
    {
       channel = 1;
	   volume_level = 40;
	   on = false;	
    }
    
    void turnOn()
    {
    	on = true;
    }
    
    void turnOff()
    {
    	on = false;
    }
    
    void setChannel(int new_channel)
    {
    	if(on && new_channel >=1 && new_channel<=120)
    	{
	    	channel = new_channel;
	    }
    }
    
    void setVolume(int volume)
    {
    	if(on && volume>=0 && volume<=100)
    	{
	    	volume_level = volume;
	    }
    }
    
    void channelUp()
    {
    	if(on && channel<120)
    	    channel++;
    }
    
    void channelDowm()
    {
    	if(on && channel>0)
    	    channel--;
    }
    
    void volumeUp()
    {
    	if(on && volume_level<100)
    	   volume_level++;
    }
    
    void volumeDown()
    {
    	if(on && volume_level>0)
    	   volume_level--;
    }
    
};
int main(int argc, char *argv[])
{
    TV tv1;
    cout << "The state of tv is " << tv1.on << endl;
    cout << "The channel is " << tv1.channel << endl;
    cout << "The volume is " << tv1.volume_level << endl;
    
    tv1.turnOn();
    tv1.setChannel(56);
    tv1.setVolume(60);
    cout << "The state of tv is " << tv1.on << endl;
    cout << "The channel is " << tv1.channel << endl;
    cout << "The volume is " << tv1.volume_level << endl;
    
    tv1.channelUp();
    tv1.volumeDown();
    cout << "The state of tv is " << tv1.on << endl;
    cout << "The channel is " << tv1.channel << endl;
    cout << "The volume is " << tv1.volume_level << endl;
    
    return 0;
}

2.建構函式

  建構函式可以理解為一種特殊的函式,與普通的函式相比,主要不同點有:

  1.建構函式的名字必須與類的名字相同

  2.建構函式沒有返回型別  返回void也不可以

  3.建立物件時,建構函式被呼叫, 他的作用就是初始化物件

建構函式也可以過載(可以同名,但函式簽名不同),建構函式用來初始化資料域。

注: 類中的變數作為類的新成員,在宣告時不能進行初始化。比如Circle類裡面的radius,在宣告不能初始化,只能在構造方法中為其賦值。

3.建立及使用物件

物件建立後,可以通過.運算(即物件成員訪問運算子)來訪問物件的資料以及呼叫物件的函式

儘量將類名的每個單詞首字母大寫

“=”可以進行兩個物件之間內容的複製,但他們仍然是兩個不同的物件

@@,一個物件包含的資料儲存在記憶體裡,但是函式並不需要儲存,因為函式是這個類所有物件共享的,編譯器僅僅建立一份拷貝就可以了。例如對於circle1, circle2,他們的大小都是一個double型別所佔的位元組的大小。

@@有時建立一個物件,但只需要使用一次,這時無需為物件命名,建立為匿名物件即可

3.類定義和類實現的分離

   分離類定義和類實現有利於類的維護。

   使用類的程式稱為客戶程式。

  ::稱為二元作用域解析運算子,指明類成員的作用範圍。

   分離的好處:

  1.可以實現隱藏。在不改變類的定義的前提下,可以自由修改類的實現

  2.作為軟體供應商,只要提供類定義的檔案和類實現的目的碼,從而隱藏了類實現的原始碼,保護軟體上的知識產產權

  類定義放在h檔案中,類實現在.cpp檔案中

 .h檔案中類的定義

// 關於類的定義
class Circle 
{
   public:
   // 定義資料域 
   double radius;
   // 構建函式 
   Circle();
   // 構建函式
   Circle(double);
   // 定義函式
   double getArea(); 
   	
} 

 

.cpp檔案中類的實現

#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"

Circle::Circle()
{
	radius = 1.0;
}

Circle::Circle(double new_radius)
{
	radius = new_radius;
}

double Circle::getArea()
{
	return 3.14*radius*radius;
}

在main.cpp中呼叫:

#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"

using namespace std;

int main(int argc, char *argv[])
{
	Circle c1;
	Circle c2(5);
	
	cout << "The radius of c1 is " << c1.radius << endl;
	cout << "The area of c1 is " << c1.getArea() << endl;
	
	cout << "The radius of c2 is " << c2.radius << endl;
	cout << "The area of c2 is " << c2.getArea() << endl;
	return 0;
}

注: include 應該包含circle.h的完整路徑,否則會報錯

4.避免多次包含

Head.h檔案

#include circle.h

Test.cpp檔案:

#include circle.h

#include head.h

     在上面的程式碼中,circle.h被重複包含,編譯器會報錯

     如何解決在一個程式中多次包含相同的標頭檔案。如果多次包含,C++編譯器會報錯,因為前處理器會把#include後的內容直接插入到他們被包含的位置,如果重複包含,就相當於重複插入了相同的內容,就會出現類有多個定義的報錯。

包含保護: 原語句 #ifndef和#define可以避免標頭檔案多次被包含,所以在標頭檔案中應該包含。

// 關於類的定義
#ifndef CIRCLE_H
#define CIRCLE_H 
class Circle 
{
   public:
   // 定義資料域 
   double radius;
   // 構建函式 
   Circle();
   // 構建函式
   Circle(double);
   // 定義函式
   double getArea(); 
   	
} ;
#endif


 

 先測試CIRCLE_H是否已經定義,如果沒有,則定義,並且把標頭檔案的其他部分也包含進來,否則跳過、

5. 資料域封裝

 資料域私有可以保護資料,使類便於維護。

例如,對於類Circle,要防止客戶程式直接修改radius的值,以防止客戶程式直接修改類的屬性,因此,使用關鍵字private,將資料域設為私有,這就是資料域封裝。

一個私有的程式,無法通過直接引用類物件來訪問它。 如果需要訪問,需改,需要定義一個get()函式和一個set()函式,即訪問器(accessor)和更改器(mutator)

Circle類:

circle.h檔案

// 關於類的定義
#ifndef CIRCLE_H
#define CIRCLE_H 
class Circle 
{
   private:       // 資料域封裝
   double radius;
   public:
   // 定義資料域 
   //double radius;
   // 構建函式 
   Circle();
   // 構建函式
   Circle(double);
   // 定義函式
   double getArea(); 
   // define accessor
   double getRadius();
   // define mutator
   void setRadius(double);
   	
} ;
#endif


 

circle.cpp檔案

// 類的實現 
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"

Circle::Circle()
{
	radius = 1.0;
}

Circle::Circle(double new_radius)
{
	radius = new_radius;
}

double Circle::getArea()
{
	return 3.14*radius*radius;
}

double Circle::getRadius()    // 訪問器
{
	return radius;
}

void Circle::setRadius(double new_radius)    // 更改器
{
	radius = (new_radius>=0) ? new_radius : 0;  //語法糖
}

客戶端程式:

#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"

using namespace std;

int main(int argc, char *argv[])
{
	//Circle c1;
	Circle c2(5);
	
	cout << "The radius of c2 is " << c2.getRadius() << endl;
	cout << "The area of c2 is " << c2.getArea() << endl;
	
	c2.setRadius(10.5);
	cout << "The radius of c2 is " << c2.getRadius() << endl;
	cout << "The area of c2 is " << c2.getArea() << endl;
	return 0;
}

6.變數作用域

全域性變數

區域性變數

區域性靜態變數

在類中,資料域被定義為便變數的形式,可以被所有成員函式訪問

在類中,如果一個區域性變數和一個數據域有相同的名字,資料域將被覆蓋,區域性變數的優先順序是最高的

7.類的抽象和封裝

銀行獲取貸款的例子:

Loan:

資料域: 利率, 貸款額度, 貸款年限 (用private實現類的封裝)

構造方法: Loan()以及Loan(int, double , double)

函式:

year(access,  mutator),  

loan_amount(access,  mutator)

interest_rate(access,  mutator)

getMonthlyPayment()

getTotalPayment()

程式碼:

Loan.h檔案:

// loan的定義 
#ifndef LOAN_H
#define LOAN_H

class Loan
{
	public:
	// 構造方法
	Loan();
	Loan(int year, double loan_amount, double year_interest_rate);
	 
	int getYear();  // accessor for year
	void setYear(int);  // mutator for year
	
	double getYearInterestRate();  // accessor for interest rate
	void setYearInterestRate(double);  //  mutator for interest rate
	
	double getLoanAmount();  // access for LoanAmount
	void setLoanAmount(double);   //mutator for
	
	double getMonthPayment();
	double getTotalPayment();
	
	private:
	int years;
	double loan_amounmt;
	double year_interest_rate;
	//double month_payment;
	//double total_payment;
};

#endif 

Loan.cpp檔案:  

// 類的實現 
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"
#include <cmath>

Loan::Loan()
{
	years = 5;
	loan_amounmt = 100000;
	year_interest_rate = 4;
}

Loan::Loan(int year, double amounmt, double rate)   // 在類的實現中,引數的名字不能與變數的名字相同 
{
    years = year;
	loan_amounmt = amounmt;
	year_interest_rate = rate;	
}

int Loan::getYear()
{
	return years;
}

void Loan::setYear(int year)
{
	years = year;
}

double Loan::getYearInterestRate()
{
	return year_interest_rate;
}

void Loan::setYearInterestRate(double rate)
{
	year_interest_rate = rate;
}

double Loan::getLoanAmount()
{
	return loan_amounmt;
}

void Loan::setLoanAmount(double amounmt)
{
	loan_amounmt = amounmt;
}

double Loan::getMonthPayment()
{
	double month_interest_rate = year_interest_rate / 1200;
	return loan_amounmt * month_interest_rate / (1 - pow(1 / (1+month_interest_rate), years * 12)); 
}

double Loan::getTotalPayment()
{
    return getMonthPayment() * 12 * years;	
}

注:在類的實現中函式引數的命名與類中的資料域命名應該不一樣,否則會有錯誤(程式不報錯,但會出現錯誤的結果)

使用者程式:

#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"

using namespace std;

int main(int argc, char *argv[])
{
    Loan loan_1;
	cout << "The year is " << loan_1.getYear() << endl;
	cout << "loan amount is " << loan_1.getLoanAmount() << endl; 
	cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
	cout << "month payment is " << loan_1.getMonthPayment() << endl;
	cout << "total payment is " << loan_1.getTotalPayment() << endl;   

	
	loan_1.setYear(10);
	loan_1.setYearInterestRate(8.5);
	loan_1.setLoanAmount(80000);
	cout << "-----------------------------" << endl;
	cout << "The year is " << loan_1.getYear() << endl;
	cout << "loan amount is " << loan_1.getLoanAmount() << endl; 
	cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
	cout << "month payment is " << loan_1.getMonthPayment() << endl;
	cout << "total payment is " << loan_1.getTotalPayment() << endl; 
	
	Loan loan_2(15, 30000, 6.4);
	cout << "-----------------------------" << endl;
	cout << "The year is " << loan_2.getYear() << endl;
	cout << "loan amount is " << loan_2.getLoanAmount() << endl; 
	cout << "loan rate is " << loan_2.getYearInterestRate() << endl;
	cout << "month payment is " << loan_2.getMonthPayment() << endl;
	cout << "total payment is " << loan_2.getTotalPayment() << endl; 
    
   	return 0;
	
}