C++(5)——new和淺拷貝問題

2020-08-10 18:29:44

前幾天面試寧波銀行的時候面試官問:C和C++的區別是什麼?什麼是OOP?
靚仔語塞。。。。
C是程序導向的語言,C++是物件導向的語言
OOP(物件導向(工資)程式設計) OOD(物件導向的設計),OOA(物件導向的分析)
舉個最簡單點的例子來區分 程序導向和麪向物件
有一天你想吃魚香肉絲了,怎麼辦呢?你有兩個選擇
1、你要自己去準備原材料。
2、去飯店!
看出來區別了嗎?這就是1是程序導向,2是物件導向。
物件導向有什麼優勢呢?首先你不需要知道魚香肉絲是怎麼做的。如果你突然不想吃魚香肉絲了,想吃別的菜,對於1需要重新買菜,買調料什麼的。對於2,老闆!那個魚香肉絲換成洛陽白菜吧,提高了可維護性。
OOP私自昂的三大特徵:封裝、繼承、多型

new/delete關鍵字

C++使用new和delete來開闢和釋放空間
重定位new: 在new和型別之間加一個地址,表示在棧上的這個變數的某一個位元組開闢一片自由儲存區
int a;
在a的記憶體單元中選擇一個記憶體單元儲存a

(重點!!!面試必問)new和malloc 的區別
1、malloc的返回值不安全需要進行型別轉換,而new不需要。
2、new是一個關鍵字、malloc是一個函數
3、malloc需要使用者輸入開闢記憶體的位元組大小,呢問,不需要計算開闢記憶體的大小。
4、new開闢記憶體失敗拋出bad_alloc異常,malloc開闢記憶體失敗返回空指針
5、malloc在堆上開闢記憶體,new開闢的空間叫做自由儲存區。
6、malloc只能開闢空間不負責初始化,new不僅可以開闢空間還可以初始化
7、開闢動態陣列的時候new [i] 而malloc(總位元組數)

爲什麼不直接操作堆記憶體,而是通過指針指向簡介操作?
動態開闢的堆記憶體沒有變數名,只能把堆記憶體的所有權交給棧上一個有變數名的指針來進行管理

穿插一個問題:堆和棧的區別是什麼?
1.棧:由操作系統自動分配釋放 ,存放函數的參數值,區域性變數的值等。其操作方式類似於數據結構中的棧;
	堆: 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收,分配方式倒是類似於鏈表。
2、數據結構:堆可以看作一棵樹,而棧是一種先進後出的數據結構。

用類實現一個簡單的回圈陣列

建構函式:在建立物件的時候初始化物件。
解構函式:在物件生命週期到達用來復原物件。
建構函式和解構函式的名字和類名一樣、沒有返回值
在建構函式中也可以用初始化列表
我們先實現一個簡單的回圈佇列

class Queue
{
public:
	Queue(int size1 = 20)
	{
		_pQue = new int[size1];
		front = rear = 0;
		size = size1;
	}
	~Queue()
	{
		delete[]_pQue;
		_pQue = nullptr;
	}
	void push(int val)
	{
		if (full())
			resize();
		_pQue[rear] = val;
		rear = (rear + 1) % size;
	}
	void pop()
	{
		if (empty())
		{
			return;
		}
		front = (front + 1) % size;
	}
	int top()//獲取隊頭元素
	{
		return _pQue[front];
	}
	bool full() { return (rear + 1) % size == front; }
	bool empty() {
		return front == rear;
	}
	void resize()
	{
		int *ptmp = new int[size * 2];
		int index = 0;
		for (int i = front;i != rear;i = (i + 1) % size)
		{
			ptmp[index++] = _pQue[i];
		}
		delete[]_pQue;
		_pQue = ptmp;
		front = 0;
		rear = index;
		size *= 2;
		ptmp = nullptr;
	}
	Queue(const Queue &src)
	{
		size = src.size;
		front = src.front;
		rear = src.rear;
		_pQue = new int[size];
		for (int i = front;i != rear;i = (i + 1) % size)
			_pQue[i] = src._pQue[i];
	}
	Queue& operator = (const Queue &src)
	{
		if (this == &src)
		{
			return *this;
		}
		delete[]_pQue;
		size = src.size;
		front = src.front;
		rear = src.rear;
		_pQue = new int[size];
		for (int i = front;i != rear;i = (i + 1) % size)
			_pQue[i] = src._pQue[i];
		return *this;
	}
private:
	int *_pQue;//申請佇列的陣列空間
	int front;//對頭
	int rear;//隊尾元素的後繼位置
	int size;
};
int main()
{
	Queue si;
	for (int i = 0;i < 20;++i)
	{
		si.push(rand() % 100);
	}
	while (!si.empty())
	{
		cout << si.top() << endl;
		si.pop();
	}
	Queue s2 = si;
	si.resize();
	getchar();
	return 0;
}

淺拷貝問題

在動態開闢的陣列進行拷貝的時候進行拷貝的時候發生淺拷貝問題,隨後在解構函式中呼叫delete時出現錯誤。
下面 下麪手寫一個深拷貝的String類

class String
{
public:
	String(const char *str = nullptr)
	{
		if (str != nullptr)
		{
			m_data = new char[strlen(str) + 1];
			strcpy(this->m_data, str);
		}
		else
		{
			m_data = new char[1];
			*m_data = '\0';
		}
	}
	String(const String &other)
	{
		m_data = new char[strlen(other.m_data) + 1];
		strcpy(this->m_data, other.m_data);
	}
	~String(void)
	{
		delete[]m_data;
	}
	String& operator = (const String &other)
	{
		//返回this的參照,即返回this本身
		if (this == &other)
		{
			return *this;
		}
		delete[]m_data;
		m_data = new char[strlen(other.m_data) + 1];
		strcpy(this->m_data, other.m_data);
		return *this;
	}
private:
	char *m_data;
};
int main()
{
	String str1;
	String str2("hello");
	return 0;
}