極客班GeekBand - C++面向對象高級開發 - 2
講師 - 侯捷
複習Complex類的實現過程
Complex.h
#ifndef __COMPLEX__
#define __COMPLEX__
#include <iostream>
using namespace std;
class complex {
private:
double re, im;
public:
complex(double r = 0, double i = 0) :re(r), im(i) {
}
complex& operator += (const complex&);
double real() const {
return re;
}
double imag() const {
return im;
}
friend complex& __doapl(complex*, const complex&);
};
inline complex& complex::operator+= (const complex& r) {
return __doapl(this, r);
}
inline complex& __doapl(complex* ths, const complex& r) {
ths->re += r.re;
ths->im += r.im;
return *ths;
}
inline complex operator +(const complex& x, const complex& y) {
return complex(x.real() + y.real(), x.imag() + y.imag());
}
inline complex operator +(const complex& x, double y) {
return complex(x.real() + y, x.imag() + y);
}
inline complex operator +(double x, complex& y) {
return complex(x + y.real(), y.imag());
}
ostream& operator <<(ostream& os, const complex& x) {
os << "(" << x.real() << "," << x.imag() << ")";
return os;
}
#endif
Complex-test.cpp
#include "Complex.h"
int main() {
complex c1(3, 6);
c1 += 5;
cout << c1 << endl;
complex c2;
c2 = 5 + c1;
cout << c2 << endl;
cout << c1 << c2 << endl;
return 0;
}
三大函數:拷貝構造,拷貝複製,析構
String.h
#include "String.h"
int main() {
String s1;
String s2("hello");
String s3(s1); //拷貝構造函數
cout << s3 << endl;
s3 = s2; //拷貝賦值函數
cout << s3 << endl;
return 0;
}
String-test.h
#ifndef __MYSTRING__
#define __MYSTRING__
#include <iostream>
using namespace std;
#include <string.h>
class String{
public:
String(const char* cstr);
//class with a pointer members
String(const String& str);
String& operator=(const String& str);
~String();
char* get_c_str() const {
return m_data;
}
private:
char* m_data;
};
inline String::String(const char* cstr = 0) {
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else {
m_data = new char[1];
*m_data = '\0';
}
}
inline String::String(const String& str) {
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
}
inline String& String::operator=(const String& str) {
//檢測是否自我賦值
if (this == &str)
return *this;
delete [] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
inline String::~String() {
delete[] m_data;
}
ostream& operator<<(ostream& os, const String& str) {
os << str.get_c_str();
return os;
}
#endif
棧、堆與內存管理
Stack VS. Heap
Stack,是存在於某作用域(scope)的一塊內存空間(memory space)。例如當你調用函數,函數本身即會形成一個stack用來放置它所接收的參數,以及返回地址。
在函數本體(Function Body)內聲明的任何變量,其所使用的內存塊都取自上訴stack。
Heap,或稱爲system heap,是指由操作系統提供的一塊global內存空間,程序可動態分配(dynamic allocated)從某中獲得若干區塊(blocks)。
class Complex {
};
{
Complex c1(1, 2); //c1所佔用的空間來自stack
Complex* p = new Complex(3); //Complex(3)是個臨時變量,所佔用的空間是以new動態分配而得,並由p指向。佔用空間來自heap。
}
stack objects、static local objects、global objects的生命期
class Complex {
};
Complex c3(1, 2);
{
Complex c1(1, 2);
static Complex c2(1, 2);
}
int main() {
}
- c1便是所謂stack object,其生命在作用域(scope)結束之際介紹。這種作用域內的object,又稱爲auto objects,因爲它會被”自動“清理。
- c2便是所謂static object,其生命在作用域(scope)結束之後仍然存在,直到整個程序結束。
- c3便是所謂global object,其生命在整個程序結束之後才結束。你也可以把它視爲一種static object,其作用域是整個程序。
heap objects的生命週期
class Complex {
};
{
Complex* p = new Complex;
delete p;
}
- p所指的便是heap object,其生命在它被delete之際結束。
class Complex {
};
{
Complex* p = new Complex;
}
- 以上出現內存泄露(memory leak),因爲當作用域結束,p所指的heap object仍然存在,但指針p的生命卻結束了,作用域之外再也看不見p(也就沒有機會delete p)
new:先分配memory,再調用ctor
Complex* pc = new Complex(1, 2);
編譯器轉化爲:
Complex* pc;
void* mem = operator new(sizeof(Complex)); //分配內存,內部調用malloc(n)
pc = static_cast<Complex*>(mem); //轉型
pc->Complex::Complex(1, 2); //構造函數
delete:先調用dtor,在釋放memory
String* ps = new String("Hello");
delete ps;
編譯器轉化爲:
String::~String(ps); //析構函數
operator delete(ps); //釋放內存,內部調用free(ps)
動態分配所得內存塊(memory block),in VC
動態分配所得的array
以上兩部分略,這兩部分侯捷老師主要爲說明的是delete和delete[]的區別。其實就是,開闢的數組就用delete[],否則可能會內存泄露,爲什麼是可能?因爲:
int* p = new int[1];
複習String類的實現過程
略,同三大函數:拷貝構造,拷貝複製,析構部分。