C和C++招待所.doc_第1页
C和C++招待所.doc_第2页
C和C++招待所.doc_第3页
C和C++招待所.doc_第4页
C和C++招待所.doc_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

窗体顶部C/C+招待所甲乙丙丁的BLOG Donews Blog| Donews首页| Donews社区| Donews邮箱| 我的首页| 联系作者| 聚合 | 登录 22篇文章: 0篇收藏: 0篇评论: 0个Trackbacks 文章 c(RSS) c+(RSS)收藏相册vc程序员 微软msdn存档 2005年04月(3) 2005年03月(5) 2005年02月(13) 2005年01月(1)2005年04月30日每日收集资料汇总(4.30)摘要:每日收集资料汇总(4.30)(全文共392字)点击此处阅读全文发表于 2005年04月30日 11:43 PM | 评论 (0)2005年04月29日每日收集资料汇总(4.29)摘要:每日收集资料汇总(4.29)(全文共1108字)点击此处阅读全文发表于 2005年04月29日 11:50 PM | 评论 (0)2005年04月25日每日收集资料汇总摘要:每日收集资料汇总(全文共1160字)点击此处阅读全文发表于 2005年04月25日 6:50 PM | 评论 (0)2005年03月24日STL/ C+ STL轻松导学 /resource/stlintro/stlintro.html发表于 2005年03月24日 5:25 PM | 评论 (0)2005年03月21日STL实践指南 Practical Guide to STLSTL实践指南 Practical Guide to STL作者:Jeff Bogan 翻译:周翔译者注这是一篇指导您如何在Microsoft Visual Studio下学习STL并进行实践的文章。这篇文章从STL的基础知识讲起,循序渐进,逐步深入,涉及到了STL编写代码的方法、STL代码的编译和调试、命名空间(namespace)、STL中的ANSI / ISO字符串、各种不同类型的容器(container)、模板(template)、游标(Iterator)、算法(Algorithms)、分配器(Allocator)、容器的嵌套等方面的问题,作者在这篇文章中对读者提出了一些建议,并指出了使用STL时应该注意的问题。这篇文章覆盖面广,视角全面。不仅仅适合初学者学习STL,更是广大读者使用STL编程的实践指南。STL简介STL (标准模版库,Standard Template Library)是当今每个从事C+编程的人需要掌握的一项不错的技术。我觉得每一个初学STL的人应该花费一段时间来熟悉它,比如,学习STL时会有急剧升降的学习曲线,并且有一些命名是不太容易凭直觉就能够记住的(也许是好记的名字已经被用光了),然而如果一旦你掌握了STL,你就不会觉得头痛了。和MFC相比,STL更加复杂和强大。STL有以下的一些优点: 可以方便容易地实现搜索数据或对数据排序等一系列的算法; 调试程序时更加安全和方便; 即使是人们用STL在UNIX平台下写的代码你也可以很容易地理解(因为STL是跨平台的)。背景知识写这一部分是让一些初学计算机的读者在富有挑战性的计算机科学领域有一个良好的开端,而不必费力地了解那无穷无尽的行话术语和沉闷的规则,在这里仅仅把那些行话和规则当作STLer们用于自娱的创造品吧。使用代码本文使用的代码在STL实践中主要具有指导意义。一些基础概念的定义模板(Template)类(以及结构等各种数据类型和函数)的宏(macro)。有时叫做甜饼切割机(cookie cutter),正规的名称应叫做范型(generic)一个类的模板叫做范型类(generic class),而一个函数的模板也自然而然地被叫做范型函数(generic function)。STL标准模板库,一些聪明人写的一些模板,现在已成为每个人所使用的标准C+语言中的一部分。容器(Container)可容纳一些数据的模板类。STL中有vector,set,map,multimap和deque等容器。向量(Vector)基本数组模板,这是一个容器。游标(Iterator)这是一个奇特的东西,它是一个指针,用来指向STL容器中的元素,也可以指向其它的元素。Hello World程序我愿意在我的黄金时间在这里写下我的程序:一个hello world程序。这个程序将一个字符串传送到一个字符向量中,然后每次显示向量中的一个字符。向量就像是盛放变长数组的花园,大约所有STL容器中有一半是基于向量的,如果你掌握了这个程序,你便差不多掌握了整个STL的一半了。/程序:vector演示一/目的:理解STL中的向量/ #include stdafx.h -如果你使用预编译的头文件就包含这个头文件#include / STL向量的头文件。这里没有.h。#include / 包含cout对象的头文件。using namespace std; /保证在程序中可以使用std命名空间中的成员。char* szHW = Hello World; /这是一个字符数组,以”0”结束。int main(int argc, char* argv) vector vec; /声明一个字符向量vector (STL中的数组) /为字符数组定义一个游标iterator。 vector :iterator vi; /初始化字符向量,对整个字符串进行循环, /用来把数据填放到字符向量中,直到遇到”0”时结束。 char* cptr = szHW; / 将一个指针指向“Hello World”字符串 while (*cptr != 0) vec.push_back(*cptr); cptr+; / push_back函数将数据放在向量的尾部。 / 将向量中的字符一个个地显示在控制台 for (vi=vec.begin(); vi!=vec.end(); vi+) / 这是STL循环的规范化的开始通常是 != , 而不是 / 因为 在一些容器中没有定义。 / begin()返回向量起始元素的游标(iterator),end()返回向量末尾元素的游标(iterator)。 cout *vi; / 使用运算符 “*” 将数据从游标指针中提取出来。 cout endl; / 换行 return 0;push_back是将数据放入vector(向量)或deque(双端队列)的标准函数。Insert是一个与之类似的函数,然而它在所有容器中都可以使用,但是用法更加复杂。end()实际上是取末尾加一(取容器中末尾的前一个元素),以便让循环正确运行它返回的指针指向最靠近数组界限的数据。就像普通循环中的数组,比如for (i=0; i6; i+) ari = i; ar6是不存在的,在循环中不会达到这个元素,所以在循环中不会出现问题。STL的烦恼之一初始化STL令人烦恼的地方是在它初始化的时候。STL中容器的初始化比C/C+数组初始化要麻烦的多。你只能一个元素一个元素地来,或者先初始化一个普通数组再通过转化填放到容器中。我认为人们通常可以这样做:/程序:初始化演示/目的:为了说明STL中的向量是怎样初始化的。#include / 和相同#include using namespace std;int ar10 = 12, 45, 234, 64, 12, 35, 63, 23, 12, 55 ;char* str = Hello World;int main(int argc, char* argv) vector vec1(ar, ar+10); vector vec2(str, str+strlen(str); return 0;在编程中,有很多种方法来完成同样的工作。另一种填充向量的方法是用更加熟悉的方括号,比如下面的程序:/程序:vector演示二/目的:理解带有数组下标和方括号的STL向量#include #include #include using namespace std;char* szHW = Hello World;int main(int argc, char* argv) vector vec(strlen(sHW); /为向量分配内存空间 int i, k = 0; char* cptr = szHW; while (*cptr != 0) veck = *cptr; cptr+; k+; for (i=0; ivec.size(); i+) cout veci; cout ”移位运算符混淆。比如vector list veclis;这样写会报错,而这样写:vector list veclis;就可以避免错误。另一种容器集合(set)这是微软帮助文档中对集合(set)的解释:“描述了一个控制变长元素序列的对象(注:set 中的key和value是Key类型的,而map中的key和value是一个pair结构中的两个分量)的模板类,每一个元素包含了一个排序键(sort key)和一个值(value)。对这个序列可以进行查找、插入、删除序列中的任意一个元素,而完成这些操作的时间同这个序列中元素个数的对数成比例关系,并且当游标指向一个已删除的元素时,删除操作无效。”而一个经过更正的和更加实际的定义应该是:一个集合(set)是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集合中的元素按一定的顺序排列,并被作为集合中的实例。如果你需要一个键/值对(pair)来存储数据,map是一个更好的选择。一个集合通过一个链表来组织,在插入操作和删除操作上比向量(vector)快,但查找或添加末尾的元素时会有些慢。下面是一个例子:/程序:set演示/目的:理解STL中的集合(set)#include #include #include using namespace std;int main(int argc, char* argv) set strset; set :iterator si; strset.insert(cantaloupes); strset.insert(apple); strset.insert(orange); strset.insert(banana); strset.insert(grapes); strset.insert(grapes); for (si=strset.begin(); si!=strset.end(); si+) cout *si ; cout endl; return 0;/ 输出: apple banana cantaloupes grapes orange/注意:输出的集合中的元素是按字母大小顺序排列的,而且每个值都不重复。如果你感兴趣的话,你可以将输出循环用下面的代码替换:copy(strset.begin(), strset.end(), ostream_iterator(cout, );.集合(set)虽然更强大,但我个人认为它有些不清晰的地方而且更容易出错,如果你明白了这一点,你会知道用集合(set)可以做什么。所有的STL容器容器(Container)的概念的出现早于模板(template),它原本是一个计算机科学领域中的一个重要概念,但在这里,它的概念和STL混合在一起了。下面是在STL中出现的7种容器:vector(向量)STL中标准而安全的数组。只能在vector 的“前面”增加数据。deque(双端队列double-ended queue)在功能上和vector相似,但是可以在前后两端向其中添加数据。 list(列表)游标一次只可以移动一步。如果你对链表已经很熟悉,那么STL中的list则是一个双向链表(每个节点有指向前驱和指向后继的两个指针)。set(集合)包含了经过排序了的数据,这些数据的值(value)必须是唯一的。map(映射)经过排序了的二元组的集合,map中的每个元素都是由两个值组成,其中的key(键值,一个map中的键值必须是唯一的)是在排序或搜索时使用,它的值可以在容器中重新获取;而另一个值是该元素关联的数值。比如,除了可以ar43 = overripe这样找到一个数据,map还可以通过arbanana = overripe这样的方法找到一个数据。如果你想获得其中的元素信息,通过输入元素的全名就可以轻松实现。multiset(多重集)和集合(set)相似,然而其中的值不要求必须是唯一的(即可以有重复)。multimap(多重映射)和映射(map)相似,然而其中的键值不要求必须是唯一的(即可以有重复)。注意:如果你阅读微软的帮助文档,你会遇到对每种容器的效率的陈述。比如:log(n*n)的插入时间。除非你要处理大量的数据,否则这些时间的影响是可以忽略的。如果你发现你的程序有明显的滞后感或者需要处理时间攸关(time critical)的事情,你可以去了解更多有关各种容器运行效率的话题。怎样在一个map中使用类?Map是一个通过key(键)来获得value(值)的模板类。另一个问题是你希望在map中使用自己的类而不是已有的数据类型,比如现在已经用过的int。建立一个“为模板准备的(template-ready)”类,你必须确保在该类中包含一些成员函数和重载操作符。下面的一些成员是必须的: 缺省的构造函数(通常为空) 拷贝构造函数 重载的”=”运算符你应该重载尽可能多的运算符来满足特定模板的需要,比如,如果你想定义一个类作为 map中的键(key),你必须重载相关的运算符。但在这里不对重载运算符做过多讨论了。/程序:映射自定义的类。/目的:说明在map中怎样使用自定义的类。#include #include #include #include using namespace std;class CStudentpublic : int nStudentID; int nAge;public : /缺省构造函数通常为空 CStudent() / 完整的构造函数 CStudent(int nSID, int nA) nStudentID=nSID; nAge=nA; /拷贝构造函数 CStudent(const CStudent& ob) nStudentID=ob.nStudentID; nAge=ob.nAge; / 重载“=” void operator = (const CStudent& ob) nStudentID=ob.nStudentID; nAge=ob.nAge; ;int main(int argc, char* argv) map mapStudent; mapStudentJoe Lennon = CStudent(103547, 22); mapStudentPhil McCartney = CStudent(100723, 22); mapStudentRaoul Starr = CStudent(107350, 24); mapStudentGordon Hamilton = CStudent(102330, 22); / 通过姓名来访问Cstudent类中的成员 cout The Student number for Joe Lennon is (mapStudentJoe Lennon.nStudentID) endl; return 0;TYPEDEF如果你喜欢使用typedef关键字,下面是个例子:typedef set SET_INT;typedef SET_INT:iterator SET_INT_ITER编写代码的一个习惯就是使用大写字母和下划线来命名数据类型。ANSI / ISO字符串ANSI/ISO字符串在STL容器中使用得很普遍。这是标准的字符串类,并得到了广泛地提倡,然而在缺乏格式声明的情况下就会出问题。你必须使用“”来从容器中间接地返回一个值。将这些值存储在容器中并不是一个好主意,因为每当一个新值添加到容器中或者有一个值从容器中删除,这些值就会失效。在某种程度上,游标可以看作是句柄(handle)。通常情况下游标(iterator)的类型可以有所变化,这样容器也会有几种不同方式的转变:iterator对于除了vector以外的其他任何容器,你可以通过这种游标在一次操作中在容器中朝向前的方向走一步。这意味着对于这种游标你只能使用“+”操作符。而不能使用“-”或“+=”操作符。而对于vector这一种容器,你可以使用“+=”、“”、“+”、“-=”中的任何一种操作符和“”、“”、“=”、“=”、“!=” 等比较运算符。reverse_iterator 如果你想用向后的方向而不是向前的方向的游标来遍历除 vector之外的容器中的元素,你可以使用reverse_iterator 来反转遍历的方向,你还可以用rbegin()来代替begin(),用rend()代替end(),而此时的“+”操作符会朝向后的方向遍历。 const_iterator 一个向前方向的游标,它返回一个常数值。你可以使用这种类型的游标来指向一个只读的值。const_reverse_iterator 一个朝反方向遍历的游标,它返回一个常数值。Set和Map中的排序除了类型和值外,模板含有其他的参数。你可以传递一个回调函数(通常所说的声明“predicate”这是带有一个参数的函数返回一个布尔值)。例如,如果你想自动建立一个集合,集合中的元素按升序排列,你可以用简明的方法建立一个set类:set int, greater set1greater 是另一个模板函数(范型函数),当值放置在容器中后,它用来为这些值排序。如果你想按降序排列这些值,你可以这样写:set int, less set1在实现算法时,将声明(predicate)作为一个参数传递到一个STL模板类中时会遇到很多的其他情况,下面将会对这些情况进行详细描述。STL 的烦恼之二错误信息这些模板的命名需要对编译器进行扩充,所以当编译器因某种原因发生故障时,它会列出一段很长的错误信息,并且这些错误信息晦涩难懂。我觉得处理这样的难题没有什么好办法。但最好的方法是去查找并仔细研究错误信息指明代码段的尾端。还有一个烦恼就是:当你双击错误信息时,它会将错误指向模版库的内部代码,而这些代码就更难读了。一般情况下,纠错的最好方法是重新检查一下你的代码,运行时忽略所有的警告信息。算法(Algorithms)算法是模板中使用的函数。这才真正开始体现STL的强大之处。你可以学习一些大多数模板容器中都会用到的一些算法函数,这样你可以通过最简便的方式进行排序、查找、交换等操作。STL中包含着一系列实现算法的函数。比如:sort (vec.begin()+1, vec.end()-1)可以实现对除第一个和最后一个元素的其他元素的排序操作。容器自身不能使用算法,但两个容器中的游标可以限定容器中使用算法的元素。既然这样,算法不直接受到容器的限制,而是通过采用游标,算法才能够得到支持。此外,很多次你会遇到传递一个已经准备好了的函数(以前提到的声明:predicate)作为参数,你也可以传递以前的旧值。下面的例子演示了怎样使用算法:/程序:测试分数统计/目的:通过对向量中保存的分数的操作说明怎样使用算法 #include /如果要使用算法函数,你必须要包含这个头文件。#include / 包含accumulate(求和)函数的头文件#include #include using namespace std;int testscore = 67, 56, 24, 78, 99, 87, 56;/判断一个成绩是否通过了考试bool passed_test(int n) return (n = 60);/ 判断一个成绩是否不及格bool failed_test(int n) return (n 60);int main(int argc, char* argv) int total; / 初始化向量,使之能够装入testscore数组中的元素 vector vecTestScore(testscore, testscore + sizeof(testscore) / sizeof(int); vector :iterator vi; / 排序并显示向量中的数据 sort(vecTestScore.begin(), vecTestScore.end(); cout Sorted Test Scores: endl; for (vi=vecTestScore.begin(); vi != vecTestScore.end(); vi+) cout *vi , ; cout endl; / 显示统计信息 / min_element 返回一个 _iterator_ 类型的对象,该对象指向值最小的那个元素。 /“*”运算符提取元素中的值。 vi = min_element(vecTestScore.begin(), vecTestScore.end(); cout The lowest score was *vi . endl; /与min_element类似,max_element是选出最大值。 vi = max_element(vecTestScore.begin(), vecTestScore.end(); cout The highest score was *vi . endl; / 使用声明函数(predicate function,指vecTestScore.begin()和vecTestScore.end())来确定通过考试的人数。 cout count_if(vecTestScore.begin(), vecTestScore.end(), passed_test) out of vecTestScore.size() students passed the test endl; / 确定有多少人考试挂了 cout count_if(vecTestScore.begin(), vecTestScore.end(), failed_test) out of vecTestScore.size() students failed the test endl; /计算成绩总和 total = accumulate(vecTestScore.begin(), vecTestScore.end(), 0); / 计算显示平均成绩 cout Average score was (total / (int)(vecTestScore.size() endl; return 0;Allocator(分配器)Allocator用在模板的初始化阶段,是为对象和数组进行分配内存空间和释放空间操作的模板类。它在各种情况下扮演着很神秘的角色,它关心的是高层内存的优化,而且对黑盒测试来说,使用Allocator是最好的选择。通常,我们不需要明确指明它,因为它们通常是作为不用添加的缺省的参数出现的。如果在专业的测试工作中出现了Allocator,你最好搞清楚它是什么。Embed Templates(嵌入式模版)和Derive Templates(基模板)每当你使用一个普通的类的时候,你也可以在其中使用一个STL类。它是可以被嵌入的:class CParam string name; string unit; vector vecData;或者将它作为一个基类:class CParam : public vector string name; string unit;STL模版类作为基类时需要谨慎。这需要你适应这种编程方式。模版中的模版为构建一个复杂的数据结构,你可以将一个模板植入另一个模板中(即“模版嵌套”)。一般最好的方法是在程序前面使用typedef关键字来定义一个在另一个模板中使用的模版类型。/ 程序:在向量中嵌入向量的演示。/目的:说明怎样使用嵌套的STL容器。#include #include using namespace std;typedef vector VEC_INT;int inp22 = 1, 1, 2, 0; / 要放入模板中的2x2的正则数组int main(int argc, char* argv) int i, j; vector vecvec; / 如果你想用一句话实现这样的嵌套,你可以这样写: / vector vector vecvec; / 将数组填入向量 VEC_INT v0(inp0, inp0+2); / 传递两个指针 / 将数组中的值拷贝到向量中 VEC_INT v1(inp1, inp1+2); vecvec.push_back(v0); vecvec.push_back(v1); for (i=0; i2; i+) for (j=0; j2; j+) cout vecvecij ; cout endl; return 0;/ 输出:/ 1 1/ 2 0虽然在初始化时很麻烦,一旦你将数据填如向量中,你就实现了一个变长的可扩充的二维数组(大小可扩充直到使用完内存)。根据实际需要,可以使用各种容器的嵌套组合。总结STL是有用的,但是使用过程中的困难和麻烦是再所难免的。就像中国人所说的:“如果你掌握了它,便犹如虎添翼。”相关链接:Josuttis Website :/Pretty Good Initialization Library :/vcpp/stl/PGIL.asp发表于 2005年03月21日 12:30 AM | 评论 (0)虚函数:从零开始(转)虚函数联系到多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。下面是小弟对C+的虚函数这玩意儿的理解。一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始)简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。下面来看一段简单的代码class Apublic: void print() cout”This is A”endl;class B:public Apublic: void print() cout”This is B”print(); p2-print();运行一下看看结果,哟呵,蓦然回首,结果却是两个This is A。问题来了,p2明明指向的是class B的对象但却是调用的class A的print()函数,这不是我们所期望的结果,那么解决这个问题就需要用到虚函数class Apublic: virtual void print() cout”This is A”endl; /现在成了虚函数了;class B:public Apublic: void print() cout”This is B”endl; /这里需要在前面加上关键字virtual吗?;毫无疑问,class A的成员函数print()已经成了虚函数,那么class B的print()成了虚函数了吗?回答是Yes,我们只需在把基类的成员函数设为virtual,其派生类的相应的函数也会自动变为虚函数。所以,class B的print()也成了虚函数。那么对于在派生类的相应函数前是否需要用virtual关键字修饰,那就是你自己的问题了。现在重新运行main2的代码,这样输出的结果就是This is A和This is B了。现在来消化一下,我作个简单的总结,指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。二, 虚函数是如何做到的(如果你没有看过Inside The C+ Object Model这本书,但又急切想知道,那你就应该从这里开始)虚函数是如何做到因对象的不同而调用其相应的函数的呢?现在我们就来剖析虚函数。我们先定义两个类class A /虚函数示例代码public: virtual void fun()cout1endl; virtual void fun2()cout2endl;class B:public Apublic: void fun()cout3endl; void fun2()cout4fun();毫无疑问,调用了A:fun(),但是A:fun()是如何被调用的呢?它像普通函数那样直接跳转到函数的代码处吗?No,其实是这样的,首先是取出vptr的值,这个值就是vtbl的地址,再根据这个值来到vtbl这里,由于调用的函数A:fun()是第一个虚函数,所以取出vtbl第一个slot里的值,这个值就是A:fun()的地址了,最后调用这个函数。现在我们可以看出来了,只要vptr不同,指向的vtbl就不同,而不同的vtbl里装着对应类的虚函数地址,所以这样虚函数就可以完成它的任务。而对于class A和class B来说,他们的vptr指针存放在何处呢?其实这个指针就放在他们各自的实例对象里。由于class A和class B都没有数据成员,所以他们的实例对象里就只有一个vptr指针。通过上面的分析,现在我们来实作一段代码,来描述这个带有虚函数的类的简单模型。#includeusing namespace std;/将上面“虚函数示例代码”添加在这里int main() void (*fun)(A*); A *p=new B; long lVptrAddr; memcpy(&lVptrAddr,p,4); memcpy(&fun,reinterpret_cast(lVptrAddr),4); fun(p); delete p; system(pause);用VC或Dev-C+编译运行一下,看看结果是不是输出3,如果不是,那么太阳明天肯定是从西边出来。现在一步一步开始分析void (*fun)(A*); 这段定义了一个函数指针名字叫做fun,而且有一个A*类型的参数,这个函数指针待会儿用来保存从vtbl里取出的函数地址A* p=new B; 这个我不太了解,算了,不解释这个了long lVptrAddr; 这个long类型的变量待会儿用来保存vptr的值memcpy(&lVptrAddr,p,4); 前面说了,他们的实例对象里只有vptr指针,所以我们就放心大胆地把p所指的4bytes内存里的东西复制到lVptrAddr中,所以复制出来的4bytes内容就是vptr的值,即vtbl的地址现在有了vtbl的地址了,那么我们现在就取出vtbl第一个slot里的内容memcpy(&fun,reinterpret_cast(lVptrAddr),4); 取出vtbl第一个slot里的内容,并存放在函数指针fun里。需要注意的是lVptrAddr里面是vtbl的地址,但lVptrAddr不是指针,所以我们要把它先转变成指针类型fun(p); 这里就调用了刚才取出的函数地址里的函数,也就是调用了B:fun()这个函数,也许你发现了为什么会有参数p,其实类成员函数调用时,会有个this指针,这个p就是那个this指针,只是在一般的调用中编译器自动帮你处理了而已,而在这里则需要自己处理。delete p;和system(pause); 这个我不太了解,算了,不解释这个了如果调用B:fun2()怎么办?那就取出vtbl的第二个slot里的值就行了memcpy(&fun,reinterpret_cast(lVptrAddr+4),4); 为什么是加4呢?因为一个指针的长度是4bytes,所以加4。或者memcpy(&fun,reinterpret_cast(lVptrAddr)+1,4); 这更符合数组的用法,因为lVptrAddr被转成了long*型别,所以+1就是往后移sizeof(long)的长度三, 以一段代码开始#includeusing namespace std;class A /虚函数示例代码2public: virtual void fun() coutA:funendl; virtual void fun2()coutA:fun2endl;class B:public Apublic: void fun() coutB:funendl; void fun2() coutB:fun2*fun)();fun = &A:fun2;(p-*fun)();delete p;system(pause);你能估算出输出结果吗?如果你估算出的结果是A:fun和A:fun2,呵呵,恭喜恭喜,你中圈套了。其实真正的结果是B:fun和B:fun2,如果你想不通就接着往下看。给个提示,&A:fun和&A:fun2是真正获得了虚函数的地址吗?首先我们回

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论