引例
/ *
* 定義一個型別:Cirlce,圓
* 成員:圓心座標(x, y),半徑radius
* /
class Cirlce {
public:
int x, y;
int radius;
};
int main()
{
// 定義一個物件
Circle a;
// 問題:此時這個物件a算是一個有效的物件麼?
// 看看它的x,y和radius,是亂的
// 那麼,再給它賦值不就好了麼?
a.x = 0;
a.y = 0;
a. radius = 1;
// 但是從「物件」的觀點來看,物件被建立之時,就應該是有效的,不應該存在「半成品」物件。
// 比如說,一輛車Car在造出來的時候,必須帶着輪子。如果沒有輪子,此時他還不能稱爲Car。
return 0;
}
存在問題:定義了一個物件,新建的的物件在記憶體中的值是無效的(雜亂的負值)。如何讓一個物件在被建立的時候,就賦予初始值。
解決方法:建構函式
建構函式是類的一種特殊的成員函數,建構函式不是普通的函數
class Circle {
public:
Circle()
{
x = y = 0;
radius = 1;
}
};
建構函式可以帶參數,也可以過載
class Cirlce {
...
public:
Cirlce ()
{
printf("111\n");
x = y =0;
radius = 1;
}
Circle(int x, int y, int r)
{
printf("222\n");
this->x = x;
this->y = y;
this->radius = r;
}
public:
int x, y;
int radius;
};
建構函式如何呼叫?
建構函式和普通成員函數不一樣,一般不顯示呼叫。
在建立一個物件時,建構函式被自動呼叫(由編譯器完成)
Circle a;
Circle b(1,1,4)l;
它們在內部實質上是分別呼叫了不同的建構函式,但是表面上沒有這個函數呼叫過程。
int main()
{
Circle a;
Circle b(1, 1, 4);
return 0;
}
建構函式的作用:物件一「出生」就是有效的。不存在「半成品」物件。
它可以理解爲「初始化」動作。
基本型別的初始化;
int a(10); // 將a初始化爲10, 也可以寫成int a = 10;
Student s = {1, "name"}; // struct的初始化
現在,類class的初始化使用建構函式的方式。
小結:
析:分崩離析
英文:建構函式 constructor
解構函式 destructor
解構函式也不是普通的函數
class Object {
public:
~Object()
{
}
};
注意:解構函式只能有一個,不能過載
解構函式如何呼叫?
解構函式從不顯示地呼叫,而是被編譯器自動地呼叫。
什麼時候被呼叫?物件被銷燬之時
對於區域性變數(物件),在超出變數作用域後,該物件失效
解構函式的作用?
解構函式:物件在銷燬之前,做一個清理和善後的工作。
比如,申請來的記憶體要釋放,開啓的檔案FIle*要關閉。
class StringBuffer {
public:
StringBuffer()
{
m_buffer = malloc(1024*512); // 申請記憶體
}
~StringBuffer()
{
free(m_buffer); // 釋放記憶體
}
};
class DataStore {
public:
DataStore()
{
m_head.next = NULL;
}
~DataStore()
{
// 刪除鏈表中所有節點,把所有,malloc的記憶體都free掉
}
private:
Student m_head;
};
分開寫在.h和.cpp裡時,規則和普通函數一樣
class DataStore {
public:
// 函數宣告
DataStore();
~DataStore();
};
// 函數定義,要加類名字首
DataStore::DataStore() {}
DataStore::~DataStore() {}
完整DataStore範例(Add和Find函數)
///////DataStore.h////////
struct Student {
int id;
char name[16];
Student* next;
}
class DataStore {
public:
DataStore();
~DataStore();
public:
void Add(const Student* data);
Student* Find(int id);
void Print();
private:
Student m_head;
};
///////DataStore.cpp///////
#include <stdio.h>
#include "DataStore.h"
DataStore::DataStore() // 建立資源
{
m_head.next = NULL;
}
DataStore::~DataStore() // 釋放資源
{
Student* p = m_head.next;
while(p)
{
Student* next = p->next;
free(p);
p = next;
}
}
void DataStore::Add(const Student* data)
{
// 建立物件、複製數據
Student* copy = (Student*)malloc(sizeof(Student));
*copy = *data;
// 插入一個物件到鏈表中
Student* cur = m_head.next; // 省略了this指針,直接呼叫成員變數m_head
Student* pre = &m_head; // 省略了this指針,直接呼叫成員變數m_head
while(cur)
{
if(copy->id < cur->id) // 找到這個位置
break;
pre = cur;
cur = cur->next; // 找到最後一個物件
}
// 插入到pre節點的後面
copy->next = pre->next;
pre->next = copy;
}
Student& DataStore::Find(int id)
{
Student* p = m_head.next;
while(p)
{
if(p->id == id)
return p;
p = p->next; // 下一個物件
}
return NULL;
}
void DataStore::Print()
{
Student* p = this->m_head.next; // this指針可加可不加
while(p)
{
printf("ID: %d, name: %s\n", p->id, p->name);
p = p->next; // 下一個物件
}
}
////////main.cpp////////
#include <stdio.h>
#include"DataStore.h"
int main()
{
DataStore ds;
Student nodeA = {13,"JWB",NULL};
Student *p = &nodeA;
ds.Add(p);
ds.Find(13);
ds.print();
return 0;
}
// 沒有預設值
Object();
// 所有參數都有預設值
Object(int a = 10, int b = 11);
// Object有兩個成員變數x,y
Object:x(1),y(2)
{
}
/// ///
Object: m_child(1, 2)
{
}