【原創】C++_第二週_Rectangle類的初步實現(一)

喜歡的朋友可以關注收藏一下:  http://blog.csdn.net/qq_31201973

本文實現了一個Rectangle類型,原版要求如下:

爲 Rectangle 類實現構造函數,拷貝構造函數,賦值操作符,析構函數。

 

class Shape
{                   
   int no;
};              
class Point
{
   int x;
   int y;
};              
class Rectangle: public Shape
{
   int width;
   int height;
   Point * leftUp;
public:
   Rectangle(int width, int height, int x, int y);
   Rectangle(const Rectangle& other);
   Rectangle& operator=(const Rectangle& other);
   ~Rectangle();         
};

  首先我的整體規劃是class類的聲明及對他的操作函數都寫在頭文件裏,cpp裏只放main()函數。而不是通常我們常見的聲明放在頭文件,cpp裏放定義和main()函數。這麼做的理由是我把整個class Rectangle類當做一個抽象封裝,裏面有對它的定義、操作、和依賴,我的程序裏因爲時間關係並沒有寫進位的依賴關係,但留下了擴展的餘地,待以後擴展後再給大家分享後續操作。考慮到頭文件中包含的頭文件,和cpp中包含的頭文件衝突,我採用了以下保護措施。

 

#ifndef __DATE_H__  
#define __DATE_H__  
  
  
  
#endif  

Rectangle類是由shape類派生出來的類該類包含三個成員變量width寬,height高,Point類型的指針變量leftUp (leftUp包含兩個成員x,y爲座標),因爲三個成員變量爲private,外部函數無法訪問他,所以我給Rectangle定義了三個成員函數get_width() get_height() get_leftUp(),返回width,height,Point的值。同時也給Point定義兩個成員函數get_x() get_y() ,來返回x,y的值。

 

 

	class Point
	{
	private:
		int x;
		int y;
	public:
		int get_x() const { return x; }
		int get_y() const { return y; }
	};
	class Rectangle : public Shape
	{
	private:
		int width;
		int height;
		Point * leftUp;
	public:
		Rectangle(int width1, int height1, int x1, int y1);			//構造函數	
		Rectangle(const Rectangle& other);							//拷貝構造函數
		Rectangle& operator=(const Rectangle& other);				//拷貝賦值函數
		~Rectangle();												//析構函數 只聲明不定義會出無法解析的錯誤
		int get_width() const { return width; }
		int get_height() const { return height; }
		Point* get_leftUp() const { return leftUp; }
	};

  然後就是爲Rectangle類定義構造函數,構造函數是定義的時候爲對象賦初值,我定義了兩個構造函數分爲普通構造函數和拷貝構造函數。

 

1.普通構造函數 a(),就是用默認參數構造。

2.拷貝構造函數 a(b),就是先構造b,把b的參數傳給a構造a 。

  先來說普通構造函數,我採用初始化列表的方式初始化,前兩個賦值沒有什麼問題,第三個成員是Point的指針你開始我用leftUp->x(x1);  方法賦值,結果發現成員變量不指明默認爲private,如果用 leftUp->get_x() 來訪問的話會因爲返回的爲值不能作爲左值,所以我採用了深度拷貝的方法:leftUp(new Point(x1, y1))  ,因爲用到了Point的構造,我爲Point寫了一個構造函數。

 

Point(int x1, int y1) : x(x1), y(y1)	{  }	//	構造函數,支持指針類型深度拷貝

這樣Rectangle類的構造函數就可以正常初始化了

 

 

	inline Rectangle::Rectangle(int width1, int height1, int x1, int y1) : width(width1), height(height1), leftUp(new Point(x1, y1))	//深度拷貝,需要Point有構造函數
	{
		;
	}

然後爲了測試Rectangle類的構造函數,我定義了一個<<重載函數

 

 

ostream& operator<<(ostream& os, guo::Rectangle& str)
{
	return os << '(' << str.get_height() << ',' << str.get_width() << ',' << str.get_leftUp()->get_x() << ',' << str.get_leftUp()->get_y() << ')' << endl;
}

然後測試的時候出現了這樣的錯誤:

 



原因是windows.h裏和Rectangle衝突,最初因爲vs顯示窗口一閃而過,我採用 system("pause"); 停一下。

解決方法有兩種:

1.用getchar()代替system("pause") 。

2.把所有的類定義到命名空間中

 

namespace guo
{

}

這個問題解決以後又出現了新的問題:

 


這個問題的原因是隻在類中聲明瞭析構函數,沒有定義它,造成無法解析的錯誤,解決完這個問題後就可以正常使用了。

 

#include<iostream>
#include"Rectangle.h"
#include<Windows.h>			//這個頭文件中包含類似Rectangle的東西,會使Rectangle無法定義對象


using namespace std;
//using guo::Point;
//using guo::Shape;
//using guo::operator<<;

ostream& operator<<(ostream& os, guo::Rectangle& str)
{
	return os << '(' << str.get_height() << ',' << str.get_width() << ',' << str.get_leftUp()->get_x() << ',' << str.get_leftUp()->get_y() << ')' << endl;
}

int main()
{
	guo::Rectangle r1(1,1,1,1);		//構造函數定義法
	cout <<"r1="<< r1;
	system("pause");			//頭文件 Windows.h ,因爲vs2013不會自動添加增加  mov ah,1  int 21H mov ax,4C00H  int 21H   所以屏幕一閃而過。
	//getchar();				//也可以用這個函數等待輸入一個字符來讓程序等待,缺點是如果有輸入,很容易不好用,所以建議用命名空間解決該問題
	return 0;
}

然後定義析構函數,析構函數是對象聲明週期結束的時候調用。因爲深度拷貝採用的是堆內存,堆內存是自定義的需要用delete釋放,如果指向該內存的指針爲棧內存變量,而棧內存變量生命週期結束以後由系統收回,那麼堆內存沒有指向的指針,該內存無法收回就造成了內存泄漏,該析構函數只用調用一次delete就可以。

 

 

	inline Rectangle::~Rectangle()
	{
		delete[] leftUp;
	}

之後定義拷貝構造函數,leftUp我採用初始化列表的方式,width  height 在因爲未知原因無法用初始化列表,所以我在函數體內定義。

 

 

	inline Rectangle::Rectangle(const Rectangle& other) : leftUp(new Point(other.leftUp->get_x(), other.leftUp->get_y()))		//深度拷貝,需要Point有構造函數
	{
		width = other.width;
		height = other.height;
	}

測試:

 

 

	guo::Rectangle r1(1,1,1,1);		//構造函數定義法
	guo::Rectangle r2(2, 2, 1, 1);		//構造函數定義法
	guo::Rectangle r3(r2);		//拷貝構造函數定義法
	guo::Point p1(1, 2);		//構造函數定義法

	//cout << r1.get_height();

	cout <<"r1="<< r1;
	cout << "r2=" << r2;
	cout << "r3=" << r3;

最後定義拷貝賦值函數,分爲三步:

 

1.delete原空間

2.this->leftUp用new定義一個和Point類一樣大小的空間並賦值

3.給 width  height  賦值

但是要考慮要拷貝賦值的對象和原對象相同,這樣會自我賦值會把自己給delete掉,從而出錯。所以專門爲這塊寫一段代碼:

 

if (this == &other)		//重複自我賦值
{
	return *this;
}

這樣拷貝賦值函數就寫好了

 

 

	inline Rectangle& Rectangle::operator=(const Rectangle& other)				//拷貝賦值函數
	{
		if (this == &other)		//重複自我賦值
		{
			return *this;
		}

		delete this->leftUp;
		this->leftUp = new Point(other.leftUp->get_x(), other.leftUp->get_y());
		this->width = other.width;
		this->height = other.height;
		return *this;
	}

測試拷貝賦值函數:

 

 

	r1 = r3;

	cout << "r1=r3(拷貝賦值測試)" << endl;
	cout << "r1=" << r1;						//拷貝賦值測試

這樣Rectangle類的基本創建功能就定義好了,下週再來實現其他功能,最後放一下所以代碼。

 

 

//	本文件名  Rectangle.h			我的編程環境VS2013
/*		本程序的註釋代表僅代表個人理解,不一定完全正確,全是我親自敲上去的,如有錯誤請聯繫我						*/

#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__
#include<iostream>
namespace guo
{
	class Shape
	{
		int no;
	};
	class Point
	{
	private:
		int x;
		int y;
	public:
		Point(int x1, int y1) : x(x1), y(y1)	{  }	//	構造函數,支持指針類型深度拷貝
		int get_x() const { return x; }
		int get_y() const { return y; }
	};
	class Rectangle : public Shape
	{
	private:
		int width;
		int height;
		Point * leftUp;
	public:
		Rectangle(int width1, int height1, int x1, int y1);			//構造函數	
		Rectangle(const Rectangle& other);							//拷貝構造函數
		Rectangle& operator=(const Rectangle& other);				//拷貝賦值函數
		~Rectangle();												//析構函數 只聲明不定義會出無法解析的錯誤
		int get_width() const { return width; }
		int get_height() const { return height; }
		Point* get_leftUp() const { return leftUp; }
	};

	inline Rectangle::Rectangle(int width1, int height1, int x1, int y1) : width(width1), height(height1), leftUp(new Point(x1, y1))	//深度拷貝,需要Point有構造函數
	{
		;
	}
	
	inline Rectangle::~Rectangle()
	{
		delete[] leftUp;
	}

	inline Rectangle::Rectangle(const Rectangle& other) : leftUp(new Point(other.leftUp->get_x(), other.leftUp->get_y()))		//深度拷貝,需要Point有構造函數
	{
		width = other.width;
		height = other.height;
	}

	inline Rectangle& Rectangle::operator=(const Rectangle& other)				//拷貝賦值函數
	{
		if (this == &other)		//重複自我賦值
		{
			return *this;
		}

		delete this->leftUp;
		this->leftUp = new Point(other.leftUp->get_x(), other.leftUp->get_y());
		this->width = other.width;
		this->height = other.height;
		return *this;
	}

}

#endif

 

 

//	本文件名  Rectangle.cpp			我的編程環境VS2013
/*		本程序的註釋代表僅代表個人理解,不一定完全正確,全是我親自敲上去的,如有錯誤請聯繫我						*/

#include<iostream>
#include"Rectangle.h"
#include<Windows.h>			//這個頭文件中包含類似Rectangle的東西,會使Rectangle無法定義對象


using namespace std;
//using guo::Point;
//using guo::Shape;
//using guo::operator<<;

ostream& operator<<(ostream& os, guo::Rectangle& str)
{
	return os << '(' << str.get_height() << ',' << str.get_width() << ',' << str.get_leftUp()->get_x() << ',' << str.get_leftUp()->get_y() << ')' << endl;
}

int main()
{
	guo::Rectangle r1(1,1,1,1);		//構造函數定義法
	guo::Rectangle r2(2, 2, 1, 1);		//構造函數定義法
	guo::Rectangle r3(r2);		//拷貝構造函數定義法
	guo::Point p1(1, 2);		//構造函數定義法

	//cout << r1.get_height();

	cout <<"r1="<< r1;
	cout << "r2=" << r2;
	cout << "r3=" << r3;

	r1 = r3;

	cout << "r1=r3(拷貝賦值測試)" << endl;
	cout << "r1=" << r1;						//拷貝賦值測試


	system("pause");			//頭文件 Windows.h ,因爲vs2013不會自動添加增加  mov ah,1  int 21H mov ax,4C00H  int 21H   所以屏幕一閃而過。
	//getchar();				//也可以用這個函數等待輸入一個字符來讓程序等待,缺點是如果有輸入,很容易不好用,所以建議用命名空間解決該問題
	return 0;
}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章