在VS中C++类的声明与定义

现在看着有点尴尬,不过还是老老实实一起迁移过来了…


貌似是第一篇关于代码的文章,有点惭愧啊。算了不扯了,直接进入正题。

第一篇是关于C++的,起因在于我们正在进行的数据结构课程,第一次实验课的内容是要我们用线性表来解决约瑟夫环问题。问题本身是不难的,难住我的却是如何写一个 链表的模板类。

约瑟夫环问题用链表来做更好一些,本来想实现一个线性表并不难,没想到 卡在了C++的模板类上Orz。。。最后无奈之下为了交作业,写了个int的链表急急忙忙交了上去。然后留着问题慢慢搞。下面贴出我第一次遇到的蛋疼的报错信息:

链接时错误了,这是什么意思,以前没遇到过。测试了一下,发现只要是SInglyList的函数在main函数中被调用都会报这种错,这特么就很尴尬了。说明函数定义的内容本身是没问题的,那错误会在哪里呢?向匡老师求救,觉得可能是构造函数的问题,导致建立对象的时候失败了,所以对象调用函数时自然会出现错误。

嗯,不愧匡老师,说的好像有那么一丝道理,我找了找我的构造函数

1
2
3
4
5
6
7
8
9
10
void init() {
SingleNode<E>* temp = new SingleNode<E>(NULL,NULL);
head = temp;
tail = head;
curr = head;
size = 0;
}
SinglyList() {
init();
}

我一度认为是初始化指针变量时的问题,然后一直思考自定义的变量初始化时的正确姿势Orz…

1
2
SingleNode<E>* temp;
temp = new SingleNode<E>(NULL,NULL);

然后换成了上面这个23333,C++prime白看了,不过的确排查的时候找出来一些地方写的不规范。。。

然而上面的这些都不是关键,当我觉得我的代码已经很完美的时候,还是报这样的蜜汁错误Orz…

于是我新开了一个工程慢慢的复制,运行,企图发现到底哪里出了问题。

在我一次实验中,在声明函数时先定义了一个内联函数print()然后其他的函数都是在另一个.cpp文件中定义的。结果发现只有调用这个内联函数的时候不会出错,啧,难道是只能内联函数可以?这特么不讲道理啊。我再写了一个函数定义在头文件中,当然,不是内联。然后调用这个函数就完美的运行了。。Orz

麻!萨!卡!定义和实现都只能放在头文件中?这不讲道理啊,之前在eclipse中写的套路都是声明在头文件中,定义在源文件中。一时无法解释这个问题,不过问题算是解决了,错误消除了。(我们只解决问题,不解释问题

默默贴几段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
template<typename E>
class SinglyList{
public:
SinglyList() {
init();
}
~SinglyList() {
removeall();
}
void append(E);//追加
void insert(E);//插入
void remove();//移除当前结点
void alter(E);//修改当前结点的值
int currPos();//返回当前结点的位置
void moveToStart();//将当前结点移动到head
void moveToEnd();//将当前结点移动到tail
const E& getValue()const;//取得当前结点的值
void clear();//清除所有结点 并重新初始化链表
void print();//遍历打印所有结点的值
void next();//当前结点后移一位
void prev();//当前结点前移一位
private:
SingleNode<E>* head;//头节点 无数据
SingleNode<E>* tail;//尾结点 有数据
SingleNode<E>* curr;//
int size;
//初始化时 实例化一个结点,然后head、tail、curr都为它
void init() {
SingleNode<E>* temp;
temp = new SingleNode<E>(NULL,NULL);
head = temp;
tail = head;
curr = head;
size = 0;
}
void removeall() {
while (head != NULL) {
curr = head;
head = head->next;
delete curr;
}
}
};

黄总对此发表评论:因为 template 的代码都要在编译的时候根据类型参数去生成啊 如果分开写的话编译的时候代码还没产生于是就炸了