http://www.shnenglu.com/Tveiker/archive/2011/01/08/138154.aspx本鏈接是“隨筆”寫的一篇名叫《鏈表實驗》的文章,以下是我的分析。
我理解你說的學號的問題是:一個叫X是男性年齡是22歲的學生,假設其學號是2009000,把該學生加入到鏈表之后,該學生的
學號發生了變化,不再是2009000。
如果你所說的學號問題和上面的描述一致的話,該問題產生的原因是:Student類不應該有拷貝構造函數和賦值函數。
假如為了實現Student類與STL容器搭配使用的能力(要獲得此種能力Student必須有拷貝構造函數和其他一些函數根據你所使用到的容器
和算法所要求的特殊函數,例如operator<)的話,這兩個函數也應該換種寫法,為了實現此種能力這兩個函數有以下實現方法:
(1)學號的轉移,參考STL的auto_ptr的控制權轉移策略
以上是對你碰到問題的說明,另外從你所寫的代碼中還發現了一些問題和不足之處,具體詳述如下:
問題
(1)Student的構造函數(Student()、Student(char *name,char* sex,int age))沒有把next初始化
(2)Student的拷貝構造函數沒有進行if (this != &s)的判斷
(3)Student類中的Name、Sex可以不使用char*類型(之所以把這個情況說成是問題而不是不足之處是為了以后寫代碼是少犯與指針相關的錯誤)
(4)在Student類的析構函數中不能對寫“Stu_no--;”這樣的語句,如果想實現學號重用的能夠的話就需要記錄學號的使用情況(本文不討論此問題)
不足之處
(1)形如class Student{
的代碼風格不好,應該修改為
class Student
{
(2)學號不應該是一個整數并且應該隱藏學號這一重要對象的生成方式(因為學號很可能每個學校不一樣,為了應對變化,所以對可能發生變化
的地方進行封裝)
(3)Student類不應該包含next指針
(4)Link類中的Add函數的接口設計很不合理(在使用的時候需要先構造出一個Student,這很沒有必要)
(5)Link類中的pivot作為類的成員變量不太合適并且沒有多大意義
提醒你一下:請仔細思考拷貝構造函數的意義,拷貝構造的意義簡單來說就是克隆,而你寫的代碼沒有克隆好,所以的導致了學號問題
針對上述所有問題的修改方案有三種
(1)A方案:禁止拷貝構造
(2)B方案:學號轉移 非法學號
各個方案的實現方法如下,其中對于學號的生成方法這二種方案都一樣(為了簡單起見,學號仍然采用整數)
1
/**//************************************************************************/
2
/**//* 學號生成 */
3
/**//************************************************************************/
4
5
typedef int StudentID;
6
7
class StudentIDGenerate
8

{
9
public:
10
static StudentID GenerateID()
11
{
12
return StudentBaseID++;
13
}
14
15
private:
16
static StudentID StudentBaseID;
17
};
18
19
StudentID StudentIDGenerate::StudentBaseID = 2009000;
20
21
/**//************************************************************************/
22
/**//* 鏈表節點 */
23
/**//************************************************************************/
24
template <typename T>
25
struct LinkNode
26

{
27
T m_value;
28
LinkNode<T> *m_pNext;
29
30
LinkNode() : m_pNext(NULL)
31
{
32
33
}
34
};
以上是通用代碼,下面是方案A的代碼
1
/**//************************************************************************/
2
/**//* A方案 */
3
/**//************************************************************************/
4
5
class Student
6

{
7
friend class Link;
8
9
public:
10
Student();
11
Student(string const &strName,string const &strSex, int nAge);
12
~Student();
13
14
public:
15
void display();
16
void SetValue(string const &strName,string const &strSex, int nAge);
17
int GetAge() const;
18
19
private://通過把以下函數設置為私有來實現禁止拷貝構造的能力
20
Student(const Student &);
21
Student &operator=(const Student &s);
22
23
private:
24
string m_strName;
25
int m_nAge;
26
string m_strSex;
27
StudentID m_ID;
28
};
29
30
typedef LinkNode<Student> StudentNode;
31
32
Student::Student()
33

{
34
m_ID = StudentIDGenerate::GenerateID();
35
m_nAge = 0;
36
}
37
38
Student::Student(string const &strName,string const &strSex,int nAge)
39

{
40
m_strName = strName;
41
m_strSex = strSex;
42
m_ID = StudentIDGenerate::GenerateID();
43
m_nAge = nAge;
44
}
45
46
Student::Student(const Student &s)
47

{
48
assert(false);
49
}
50
51
Student &Student::operator =(const Student &s)
52

{
53
assert(false);
54
return *this;
55
}
56
57
Student::~Student()
58

{
59
60
}
61
62
void Student::display()
63

{
64
cout<<"Name is:"<<m_strName<<" ID is:"<<m_ID<<" Sex is:"<<m_strSex<<" Age is:"<<m_nAge<<endl;
65
}
66
67
void Student::SetValue(string const &strName,string const &strSex, int nAge)
68

{
69
m_strName = strName;
70
m_strSex = strSex;
71
m_nAge = nAge;
72
}
73
74
int Student::GetAge() const
75

{
76
return m_nAge;
77
}
78
79
class Link
80

{
81
public:
82
Link();
83
~Link();
84
85
public:
86
void Delete(StudentID);
87
void Add(string const &strName,string const &strSex,int nAge);
88
void Display();
89
90
private:
91
StudentNode *m_pHead;
92
StudentNode *m_pTail;
93
};
94
95
Link::Link()//構造空鏈表
96

{
97
m_pHead=NULL;
98
m_pTail=NULL;
99
}
100
101
Link::~Link()//釋放內存
102

{
103
while (NULL != m_pHead)
104
{
105
StudentNode *pTemp = m_pHead;
106
m_pHead = m_pHead->m_pNext;
107
delete pTemp;
108
}
109
}
110
111
void Link::Add(string const &strName,string const &strSex,int nAge)//向鏈表中添加學生
112

{
113
if(m_pHead==NULL)
114
{
115
m_pHead = new StudentNode();
116
m_pHead->m_value.SetValue(strName, strSex, nAge);
117
m_pTail = m_pHead;
118
m_pTail->m_pNext = NULL;
119
}
120
else
121
{
122
m_pTail->m_pNext = new StudentNode;
123
m_pTail->m_pNext->m_value.SetValue(strName, strSex, nAge);
124
m_pTail->m_pNext->m_pNext = NULL;
125
m_pTail = m_pTail->m_pNext;
126
}
127
}
128
129
void Link::Display()//顯示鏈表中學生信息
130

{
131
cout<<endl;
132
StudentNode *pTemp = m_pHead;
133
while (NULL != pTemp)
134
{
135
pTemp->m_value.display();
136
pTemp = pTemp->m_pNext;
137
}
138
cout<<endl;
139
}
140
141
void Link::Delete(int nAge)//刪除鏈表中所有年齡為nAge的學生
142

{
143
StudentNode *pPre = m_pHead;
144
StudentNode *pCur = m_pHead;
145
while (NULL != pCur)
146
{
147
if (pCur->m_value.GetAge() == nAge)
148
{
149
if (pCur == m_pHead)
150
{
151
pPre = m_pHead = m_pHead->m_pNext;
152
}
153
else
154
{
155
pPre->m_pNext = pCur->m_pNext;
156
}
157
158
pCur->m_value.display();
159
delete pCur;
160
pCur = NULL != pPre ? pPre->m_pNext : NULL;
161
}
162
else
163
{
164
pPre = pCur;
165
pCur = pCur->m_pNext;
166
}
167
}
168
}
以下是測試方案A的代碼
void main()


{
//測試零
//vector<Student> vecStu;
//Student st1;
//vecStu.push_back(st1);

//Student st2;
//vecStu.push_back(st2);

//測試一
Link link;
link.Add("X","Boy",22);
link.Add("Y","Boy",20);
link.Add("Z","Boy",21);
link.Add("U","Girl",22);
link.Display();
link.Delete(21);
link.Display();

//測試二
Link link1;
link1.Add("X","Boy",22);
link1.Add("Y","Boy",20);
link1.Add("Z1","Boy",21);
link1.Add("Z2","Boy",21);
link1.Add("U","Girl",22);

link1.Display();
link1.Delete(21);

link1.Display();

//測試三
Link link2;
link2.Add("X","Boy",22);
link2.Add("Y","Boy",20);
link2.Add("Z1","Boy",21);
link2.Add("Z2","Boy",21);
link2.Add("U","Girl",22);

link2.Display();
link2.Delete(22);

link2.Display();

//測試四
Link link3;
link3.Add("X","Boy",22);
link3.Display();
link3.Delete(22);

link3.Display();

//測試五
Link link4;
link4.Add("X","Boy",22);
link4.Add("Y","Boy",20);
link4.Add("Z1","Boy",21);
link4.Add("Z2","Boy",21);
link4.Add("U","Girl",22);

link4.Display();
link4.Delete(1);

link4.Display();
}
其中采用方案A是測試零下面所注釋掉的代碼不能通過編譯,在VC2008的IDE下會報:class“Student”: 沒有可用的復制構造函數或復制構造函數聲明為“explicit”錯誤
為了修正此錯誤,對代碼就行了修改,也就是B方案
const StudentID ErrorStudentID = 0;//其實非法學號是個范圍[負無窮,2009000] 添加的代碼
mutable StudentID m_ID;//為了能夠在拷貝構造函數中修改該值,把其類型聲明為mutable 修改的代碼

//修改的代碼
Student::Student(const Student &s)


{
m_strName = s.m_strName;
m_strSex = s.m_strSex;
m_ID = s.m_ID;
s.m_ID = ErrorStudentID;
m_nAge = s.m_nAge;
}

//修改的代碼
Student &Student::operator =(const Student &s)


{
if (this != &s)

{
m_strName = s.m_strName;
m_strSex = s.m_strSex;
m_ID = s.m_ID;
s.m_ID = ErrorStudentID;
m_nAge = s.m_nAge;
}

return *this;
}
PS:
使用面向對象語言進行程序設計的時候一個關鍵的問題是:設計一個好的類,這里的Student類就是一個典型的例子。
學習的時候當然可以自己寫個鏈表,自己管理內存;但是在實際工作中還是要多用STL現成的容器和算法,只有這樣才能提高代碼的質量,降低錯誤發生的概率。
上面代碼實際還可以繼續進行改進,不夠寫道此種程度基本上沒有什么大問題了。
posted on 2011-01-09 07:45
OnTheWay 閱讀(1617)
評論(2) 編輯 收藏 引用 所屬分類:
個人感悟