static和 friend友元 的一点调试体验
本篇日志是作为菜鸟C++学员,写的一篇调试错误的过程,旨在记录自己的学习过程,帮助自己提高,后面附有我的代码。
今天早上在看Essential C++ P125时,想照着书上的例子写一次,看看运行结果。 结果当我抄书上的代码时,一直从书第四章开头找到了P125,原因是书上是按照函数过程这么讲的,造成我抄完代码也不知所以然,结果当然就是编译不通过了。
第一个问题:
当时第一次出现的错误是LNK2001,好像是这个编号,然后我就试,看是不是这里的问题,改一次编译一次,当然这样是没有结果的。最后我想到了百度,百度以后,得到的结果是声明的变量在另一个文件里面找不到。 也就是说这时候才找到问题原因是 class Triangular类中的private 变量 static std::vector<int> _elems在class Triangular里找不到。然后我就改这个问题,第一次是这样改的:在class Triangular的cpp里加上代码 extern _elems;第二次改成extern std::vector<int> _elems; 然后第三次改成std::vector<int> Triangular::_elems; 这时候这个问题才算解决。
收获:
之前看过C++ primer,也看过关于声明,定义这些问题,但之前都只是看书,没有体会,也更没有“一个文件里声明,另一个文件里定义”的这种体会,这次也重新回忆了一下static变量声明时,默认是有extern的,也又学习了一次extern声明和变量定义,还看到了一次一个文件里声明变量,在另一个文件里定义的情况(这里是在.h文件声明一个class的全局vector,在class的cpp文件里定义改vector)
第二个问题:
改完第一个问题后,又出现了第二个问题,在类BaseIterator里重载的operator*() 一直出错,错误类似于上述情况,都是链接时出错。当时情况是抄的书上的代码,一报错,不知道该从哪里下手,然后就找自己感觉像是错的地方,改啊改,还是报错(主要问题是Triangular和BaseIterator里互相调用对方的成员变量,我就这里加一个.h文件,继续报错;那里加一个.h,仍然报错;这里加一个class声明,报错;一直试了好长时间)。最后看着抄的一堆代码,想起了上午调试static变量的过程(调试第一个问题的过程就是单独抛开书上的这个例子,单独建了两个简单的类来做的),重新建了一个工程,然后写一个重载函数,编译一个(主要重载的就是++,这里没有调试*),最后这个测试程序运行正确。然后我就把之前抄的代码里面所有不相干的代码都注视起来,擦,还是报错。。然后,我想了个绝招,,我照着这个测试程序,把抄的程序一行一行注释起来,唯独没有改变类的名字,结果:依然报错。。这次我也不知道问题是哪了。没办法,我就重新建了一个工程EssentialCppP125Again,按照我自己的需要,先写BaseIterator这个类,写一个重载函数,编译一次,,最后成功写到了重载*函数,见到这个*我有点害怕,因为它牵扯到Triangular 类。而Triangular类之前上午写的时候就因为那个static成员变量搞了一上午。所以我就抛开课本上这个Triangular类的定义,只写自己需要的变量和函数(对于课本上的一些测试越界的函数,还有一些赋值等等的函数都省略了)。最后终于调试到了要写*的地方。Triangular类里声明友元函数 friend int BaseIterator::operator*(); 类BaseIterator里定义,又是这个A引用B,B引用A的问题,一下午就被这个问题整过去了,在群里也问了问,群友的回答是:加class Triangular;class BaseIterator;声明和引入对方对象的指针,代码如下:
1 #include<iostream>
2 using namespace std;
3 class A;
4 class B;
5
6 class A
7 {
8 public:
9 B *bb;
10 static int sta;
11 };
12
13 class B
14 {
15 public:
16 A *aa;
17 void p(){cout<<A::sta;}
18 };
19 int main(){
20
21 return 0;
22 }
这个,我还没有测试,先继续我最后的解决方法。我最后是在class BaseIterator里include Triangular.h,全部代码如下:(但这里我还是不懂为什么这样就可以通过,不懂事怎么互相引用的):(按照写的过程贴出所有代码)
1、BaseIterator类
1.1 BaseIterator.h
1 #pragma once
2 #include <iostream>
3 #include <vector>
4
5
6
7
8 class BaseIterator
9 {
10 public:
11 BaseIterator(void);
12 ~BaseIterator(void);
13 public:
14 BaseIterator(int index) : _index(index) {}
15 bool operator==(const BaseIterator& rhs) {return _index == rhs._index;}
16 bool operator!=(const BaseIterator& rhs) {return !(*this == rhs);}
17 BaseIterator& operator++();
18 BaseIterator operator++(int);
19 int operator*();
20
21 int index() {return _index;}
22
23 private:
24 int _index;
25 };
1.2 BaseIterator.cpp
1 #include "StdAfx.h"
2 #include "BaseIterator.h"
3 #include "Triangular.h"
4
5
6 //std::vector<int> Triangular::_elems;
7 BaseIterator::BaseIterator(void)
8 {
9 _index = 0;
10 }
11
12 BaseIterator::~BaseIterator(void)
13 {
14 }
15
16
17 BaseIterator& BaseIterator::operator++()
18 {
19 ++_index;
20 return *this;
21 }
22
23 BaseIterator BaseIterator::operator++(int)
24 {
25 BaseIterator tmp = *this;
26 ++_index;
27 return tmp;
28 }
29
30 int BaseIterator::operator*()
31 {
32 return Triangular::_elems[this->index()];
33 }
2 Triangular类
2.1 Triangular.h
1 #pragma once
2 #include <vector>
3 #include "BaseIterator.h"
4 class Triangular
5 {
6 public:
7 typedef BaseIterator iterator;
8
9 public:
10 Triangular(void);
11 ~Triangular(void);
12
13 public:
14 Triangular(int len);
15 int length() const { return _length;}
16 int elem(int pos) const { return _elems[pos] ;}
17
18 static void gen_elements(std::vector<int>::size_type length);
19
20 BaseIterator Triangular::begin();
21 BaseIterator Triangular::end();
22 friend int BaseIterator::operator*();
23
24 private:
25 int _length;
26
27 const static int _max_elems = 1024;
28 static std::vector<int> _elems;
29 };
2.2Triangular.cpp
1 #include "StdAfx.h"
2 #include "Triangular.h"
3 #include <iostream>
4
5 std::vector<int> Triangular::_elems;
6
7 Triangular::Triangular(void)
8 {
9 _length = 0;
10 }
11
12 Triangular::Triangular(int len)
13 {
14 _length = len >= 0 ? len : 0;
15
16 std::vector<int>::size_type elem_cnt = _length;
17
18 if ( _elems.size() < elem_cnt )
19 {
20 gen_elements(elem_cnt);
21
22 }
23 }
24
25 Triangular::~Triangular(void)
26 {
27 }
28
29 BaseIterator Triangular::begin()
30 {
31 return BaseIterator(0);
32 }
33
34 BaseIterator Triangular::end()
35 {
36 return _length > 0 ? BaseIterator(_length) : 0;
37 }
38
39 void Triangular::gen_elements(std::vector<int>::size_type length)
40 {
41 if (length < 0 || length > _max_elems)
42 {
43 std::cerr << "length < 0 or length > _max_elems" << std::endl;
44 exit(-1);
45 }
46 if (_elems.size() < length)
47 {
48 int ix = _elems.size();
49 for (; ix < length; ++ix)
50 {
51 _elems.push_back(ix*(ix+1)/2);
52 }
53 }
54 }
3、 main函数测试
1 // EssentialCppP122Again.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include "BaseIterator.h"
6
7 #include <iostream>
8 #include "Triangular.h"
9 using namespace std;
10
11
12 int _tmain(int argc, _TCHAR* argv[])
13 {
14 /*BaseIterator iter1;
15 BaseIterator iter2(1);
16
17 ++iter1;*/
18
19
20 Triangular tri(20);
21 Triangular::iterator iter1 = tri.begin();
22 Triangular::iterator iter2 = tri.end();
23 cout << "Triangular Series of " << tri.length() << " elements\n";
24 while (iter1 != iter2)
25 {
26 //cout << *iter1 << '\t' ;
27 cout << tri.elem(iter1.index()) << '\t';
28 ++iter1;
29 }
30 cout << endl;
31
32
33 return 0;
34 }
收获:
以后尽量少抄书上的代码,要在觉得自己理解的差不多以后,按照自己的想法来写出来,而不是当码字员。还有就是这样能按照逻辑过程来写代码,而不是按照书上的页码来抄代码。还有测试的时候不要把书上的所有代码功能都实现,当然这个现在也不好定,如果一直不按照规范,注意自己代码的边界检查,等等这些,可能会影响自己的习惯,但如果这样写了又可能紧紧只是一个看结果的过程而浪费很多时间。。尽量按照书上那样写完整吧,这点现在还不好体会,没法总结。
PS:Triangular类和书上的要实现的目的相差很大,我这里只是为了测试重载*,所以不是按照书上定义_elems,_beg_pos等等这些变量来写的程序。
总结:
这次测试到此结束,但问题依然还在,就是上面说的友元和互相#include "XXX.h"的问题(红色部分),这个问题先暂时遗留在这里,等后面再看到这方面知识时再回头体会,如哪位朋友正好方便告诉我这个问题的解答,还麻烦能回帖给说下书名页码或者网址链接,先谢谢各位兄弟姐妹。