1. 程式人生 > >面向物件(2)

面向物件(2)

/* OOP:封裝  繼承  多型 OOP:抽象  封裝  繼承  多型

許可權:public  private this:成員方法宣告或者定義的時候加上this指標       成員方法呼叫的時候,自動傳參this指標     在成員方法內使用成員變數的地方,加上this指標的解引用

建構函式: 初始化物件時候自動呼叫的成員方法 如果不自己實現建構函式,編譯器會預設生成一個預設建構函式 如果自己實現,則編譯器不會生成了 建構函式可以過載

拷貝構造: 用一個已經存在的物件,構造同類型的新物件 防止淺拷貝 如果不自己實現,預設生成一個淺拷貝的拷貝構造 拷貝建構函式必須傳引用

=: 用一個已經存在的物件給另一個已經存在的物件賦值 如果不自己實現,編譯器會預設生成一個淺拷貝的= 防止自賦值 防止記憶體洩露 防止淺拷貝

析構: 一個物件的生存週期滿,自動呼叫的成員方法 解構函式沒有引數,不可以過載 如果不自己實現,編譯器會預設生成 防止記憶體洩漏

*/

/* 臨時物件 顯式:出現型別名 隱式:未出現型別名

內建型別的臨時物件都是常量

自定義型別產產生的臨時物件:隱式 :常量     顯式:非常量

*/

#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;

class CGoods
{
public:
	CGoods(const char *name = NULL, int num = 0, double price = 0.0)
	{
		cout << "CGoods(const char *name, int num, double price)" << endl;
		if (NULL != name)
		{
			_name = new char[strlen(name) + 1];
			strcpy_s(_name, strlen(name) + 1, name);
		}
		else
		{
			_name = NULL;
		}
			
		_num = num;
		_price = price;
	}

	CGoods(const CGoods &src)
	{
		cout << "CGoods(const CGoods &src)" << endl;
		//_name = src._name;//error  此為淺拷貝
		_name = new char[strlen(src._name) + 1];
		strcpy_s(_name, strlen(src._name) + 1, src._name);
		_num = src._num;
		_price = src._price;
	}

	CGoods &operator=(const CGoods& src)
	{
		cout << "CGoods &operator=(const CGoods& src)" << endl;
		//防止自賦值
		if (this == &src)
		{
			return *this;
		}

		//防止記憶體洩漏
		if (_name !=- NULL)
			delete []_name;

		//防止淺拷貝
		_name = new char[strlen(src._name) + 1];
		strcpy_s(_name, strlen(src._name) + 1, src._name);
		_num = src._num;
		_price = src._price;

		return *this;
	}

	~CGoods()//先構造的後析構
	{
		cout << "~CGoods()" << endl;
		if (NULL != _name)
		{
			delete[]_name;
			_name = NULL;
		}
	}

	void show()
	{
		cout << "name:" << _name << endl;
		cout << "num:" << _num << endl;
		cout << "price:" << _price << endl;
	}

private:
	char* _name;
	int _num;
	double _price;
};

CGoods fun1(CGoods& goods)   //傳引用    //fun1(goods5):用goods5拷貝構造goods
{
	//CGoods goods1 = goods;  //用goods拷貝構造goods1
    //return goods; //用goods拷貝構造臨時量(返回值)臨時量在main函式棧幀上,不會先被析構


   //析構的時候先析構goods1  然後是goods  待返回完成後,臨時量要進行析構 緊接著析構goods5




	return "jidan";
	/*
	構造臨時物件
	拷貝構造goods6
	析構臨時物件


	直接構造
	*/
}



int main()
{
	CGoods goods1("mianbao", 20, 1.5);//構造goods1
	//CGoods goods2(goods1);//用goods1拷貝構造goods2

	//CGoods goods3 = goods2;//用goods2拷貝構造goods3   用已生成的good2構造新生成的goods3
	//goods3 = goods1;//賦值   用已生成的goods1給已生成的goods3賦值
	//CGoods goods4("xiangchang");//構造goods4
	CGoods goods5 = "latiao";//直接構造goods5
	/*
	先利用char*構造一個臨時物件 (臨時物件為CGood型別) 
	用臨時物件拷貝構造goods5    //臨時物件的生存週期僅在這一個語句
	析構臨時物件

	編譯器優化為:直接構造
	*/
	goods5 = "niunai";
	/*
	1.先構造臨時物件
	2.用臨時物件給goods5賦值
	3.析構臨時物件
    不能優化
	*/


    //const CGoods &gb = "kuangquanshui";//隱式(沒有出現型別名)產生臨時物件
	CGoods &ga = (CGoods)"fangbianmian";//顯式產生臨時物件
    //char * 強轉為CGood型別  強轉是否成功要看是否有合適的建構函式

	/*
    1.先構造臨時物件
    2.把臨時物件的引用給ga
    3.不析構

	臨時物件一旦被引用,它的生存週期就和引用相同
	*/

    //const  int &a =(int)10;//用10產生一個臨時變數,將臨時變數的地址給引用a
	//const  int &a =(int)10;//顯式產生整型的臨時物件
	//int &a = (int)10;//不允許洩露常量的引用或者地址給非常量的引用或者指標
	//int &b = 20;
	

	CGoods goods6(fun1(goods5));//用funl函式返回值的臨時物件拷貝構造goods6

	return 0;
}

自定義型別傳參都需要提前開闢空間

在記憶體空間上構造,不能在暫存器上構造