本篇日志是作为菜鸟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 #include2 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<
这个,我还没有测试,先继续我最后的解决方法。我最后是在class BaseIterator里include Triangular.h,全部代码如下:(但这里我还是不懂为什么这样就可以通过,不懂事怎么互相引用的):(按照写的过程贴出所有代码)
1、BaseIterator类
1.1 BaseIterator.h
BaseIterator.h 1 #pragma once 2 #include 3 #include 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
BaseIterator.cpp 1 #include "StdAfx.h" 2 #include "BaseIterator.h" 3 #include "Triangular.h" 4 5 6 //std::vector 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 #include3 #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 ::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 _elems; 29 };
2.2Triangular.cpp
1 #include "StdAfx.h" 2 #include "Triangular.h" 3 #include4 5 std::vector 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 ::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 ::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 #include8 #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"的问题(红色部分),这个问题先暂时遗留在这里,等后面再看到这方面知识时再回头体会,如哪位朋友正好方便告诉我这个问题的解答,还麻烦能回帖给说下书名页码或者网址链接,先谢谢各位兄弟姐妹。