class两个经典分类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #ifndef __MYSTRING__ #define __MYSTRING__
class String;
class String { public: String(const char* cstr = 0); String(const String& str); String& operator = (const String& str); ~String(); char* get_c_str() const { return m_data; } private: char* m_data; };
String::function(...)... #endif
|
构造函数如何写:
1 2 3 4 5 6 7 8 9 10 11
| 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'; } }
|
三大特殊函数:如果构造函数包含指针元素,那么类中需要包含拷贝构造,拷贝赋值与析构函数这三个函数。
- 拷贝构造:若仅使用编译器默认的拷贝函数,它会逐位拷贝指针,这样相当于有两个指针均指向同一个位置,这样的操作存在一定的危险。为避免这种情况,我们
1 2 3 4 5
| inline String::String(const String& str) { m_data = new char [strlen(str.m_data) + 1]; strcpy(m_data, str.m_data); }
|
1 2 3 4 5 6 7 8 9
| 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; }
|
1 2 3 4
| inline String::~String(){ delete[] m_data; }
|
堆栈与内存管理
1 2 3 4 5 6
| class complex {...} ... { complex c1(1,2); complex* p = new complex(3); }
|
上面表示的是两种分配内存的方式,第一种为静态分配,故c1所在的内存存在于stack中,在stack中的内存在函数执行完毕就自动释放(如果是static变量,则在程序执行完毕后释放,若不是static变量,则在作用域结束时释放)。第二种方式表示的是在heap中申请一块大小和complex类一样的内存空间,这种是动态分配。动态分配的内存空间需要手动释放。
new:我们调用new函数时,一般是先分配一块内存空间,然后调用此类的析构函数初始化此类,最后返回该内存空间的起始地址。
1 2 3 4
| String * ps; void* mem = operator new (sizeof(String)); ps = static_cast<String*>(mem); ps->String::String("hello");
|
delete:先调用析构函数,再释放内存空间。
1 2
| String::~String(ps); operator delete(ps);
|
注:array new一定要搭配array delete
1 2 3
| String* p = new String[3]; ... delete[] p;
|