专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅
在C++的子类中,定义某成员函数时,我们通常需要显式的调用其基类的版本。例如在一个绘图类结构中,子类只需要去绘制在子类添加进去的部分图形,然后再调用基类去完成基础的图形。这个成员函数有一般都是虚函数。对于构造函数,在子类的构造函数中也可能显式地执行基类的构造函数。 先看看一个例子,基类Shape的默认构造函数不分配name空间,但子类Line的默认构造函数会按照规则自动产生name,这里我们假设name是private的,如果name不是private,问题会很简单,也不会出现下述问题了。但在现实中,通常在基类的构造函数会初使化一些重要的private成员... [阅读全文] [PDF]
虚函数和多态性使得设计和实现易于扩展的系统成为可能。在程序开发过程中,不论类是否已经建立,程序员都可以利用虚函数和多态性先编写这些类对象的程序。 虚函数和多态性的程序设计无需使用switch逻辑。程序员可以用虚函数机制自动完成等价的逻辑,因而避免与switch逻辑有关的各种各样的错误。 虚函数的声明方法是在基类的函数原型前加上关键字virtual。 派生类在需要的时候可以自己实现基类的虚函数,否则就使用基类的实现。 如果用名字和圆点成员选择运算符引用一个特定的对象来调用虚函数,则被调用虚函数是在编译时确定(称为静态联编),也就是为该特定对象的类定义的函数或... [阅读全文] [PDF]
假定一组形状类(如Circle、Triangle、Rectangle和Square等等)都是从基类Shape派生出来的。在面向对象的程序设计中,我们可能要使每一个这样的类都能够绘制其自身形状。尽管每个类都有它自己的draw函数,但是绘制每种形状的draw函数却是大不相同的。当需要绘制形状时,不管它是什么形状,把它作为基类Shape的对象处理是再好不过了。然后,我们只需要简单地调用基类Shape的函数draw,并让程序动态地确定(即在执行时确定)使用哪个派生类的draw函数。 为了使这种行为可行,我们把基类中的函数draw声明为虚函数。然后在每个派生类中重新... [阅读全文] [PDF]
如果基类声明了一个函数是虚函数,而且派生类并没有改变参数,只是把函数内容改变了,那么这个可以认为是“重写“ 派生类重载是什么呢,就是在派生类中仅仅保留基类的函数名,参数变了,或者返回类型也变了,如果不改变参数仅仅改变返回类型不是重载,这样也是错的。 如果重载了,你就不会得到基类对应的函数名的函数了,被隐藏了! 除非你使用基类作用域解析符号,要不你调用基类版本就是错误的! 看例子: class C0 { public: virtual void Set1(int i) { cout <<\"C0:Set1 i=\" <<i <&... [阅读全文] [PDF]
C++中,以类、虚函数等为代表的数据抽象功能一直是C++的核心和难点。我认为C++的抽象应该是指:从我们需要解决的问题出发,在与该问题相关的一组关联对象中提取出主要的或共有的部分――说简单一点,就是用相同的行为来操作不同的对象。 从提出问题到找出与该问题相关的对象,这是一个互动的、反复的过程。在对相关对象的抽象中,随着认识的深入,我们可能会修改最初的目标,而最初目标的修改又可能使一组新的相关对象被加入进来。如:假设现在要设计一个基于广域网的邮件服务器,首先可能需要通过socket对底层协议进行封装,为高层的pop3、smtp协议提供一组标准的接口。开始为了... [阅读全文] [PDF]
以下代码没有什么实用价值,最多拿来加深一下对虚函数表的印象,一时性起,想直接操纵虚函数表。这段代码只尝试了在VS2005上编译通过,没有在其他编译器上尝试,它并不具有可移植性。 大家都知道C++的虚函数机制通常是通过一个虚函数表来实现的,C++不对内存访问做限制,所以我们可以通过指针自己访问虚函数表,然后进行操作。 #include<iostream> usingnamespacestd; classB { public: virtualvoidfun1() { cout<<\"B::fun1\"<<end... [阅读全文] [PDF]
考虑一下多线程代码,在设计上,App为了获取更多的功能,从Window派生,而App同时为了获取 某个模块的回调(所谓的Listener),App同时派生Listener,并将自己的指针交给另一个模块, 另一个模块通过该指针多态回调到App的实现(对Listener规定的接口的implemention)。设计上 只是一个很简单的Listener回调,在单线程模式下一切都很正常(后面我会罗列代码),但是换到 多线程下,编译器似乎就对语言机制的支持不够了: /**//// /// to demonstrate the fucking bug. /// #inc... [阅读全文] [PDF]
学习 C++ 的同志不知道有没有和我一样遇到过这样的困惑:C++中的虚函数到底怎么实现的?在各种继承关系中,虚函数表的结构到底是什么样的?曾经我是很想当然,可是后来在使用ATL的过程中,我发现并不是我想的那样。大家知道,利用C++语言本身的特性进行COM编程当然是很方便的事,但是你就得随时随地都知道那虚函数表里头到底是些什么东西。讲C++语法的书没有义务告诉你C++产生的虚函数表是什么样的,这就是头痛的所在。 自已做试验是件很快乐的事,我很愿意这么做。 首先写个函数,作为我们实验的基础。传入虚函数表指针,显示虚数表的内容。 void DispVFT... [阅读全文] [PDF]
一,什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应该从这里开始)简单地说,那些被virtual关键字修饰的成员函数,就是虚函数虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。下面来看一段简单的代码class A{public:void print(){ cout<<”This is A”<<endl;}};class B:public A{public:void print(){ cout... [阅读全文] [PDF]
问:为什么要把父类的析构函数定义成虚函数,,www. ?答:否则子类的析构函数可以未被调用,具体代码如下:class A {public:A(){TRACE(\"A()\\n\");};~A(){TRACE(\"~A()\\n\");};}; class B : public A {public:B(){TRACE(\"B()\\n\");};~B(){TRACE(\"~B()\\n\");};}; void CEgDlg::OnButton1() {A * p = (A*)new B() ;delete p ;}运行结果如下:A()B()~A()... [阅读全文] [PDF]
首先来说一说虚函数,所谓虚函数是这样一个概念:基类中有这么一些函数,这些函数允许在派生类中其实现可以和基类的不一样。在C++中用关键字virtual来表示一个函数是虚函数。 C++中还有一个术语“覆盖”与虚函数关系密切。所谓覆盖就是说,派生类中的一个函数的声明,与基类中某一个函数的声明一模一样,包括返回值,函数名,参数个数,参数类型,参数次序都不能有差异。(注1)说覆盖和虚函数关系密切的原因有两个:一个原因是,只有覆盖基类的虚函数才是安全的。第二个原因是,要想实现基于虚函数的多态就必须在派生类中覆盖基类的虚函数。 接下来让我们说一说为什么要有虚函数,分析一下为什么派... [阅读全文] [PDF]
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、重载的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。 这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是... [阅读全文] [PDF]
重载父类的虚函数是很显然的事情,不然,虚函数就变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了父类的虚函数,会是一个什么样子?假设,我们有下面这样的一个继承关系。 为了让大家看到被继承过后的效果,在这个类的设计中,我只重载了父类的一个函数:f()。那么,对于派生类的实例,其虚函数表会是下面的一个样子: 我们从表中可以看到下面几点, 1)重载的f()函数被放到了虚表中原来父类虚函数的位置。 2)没有被重载的函数依旧。 这样,我们就可以看到对于下面这样的程序, Base *b = new Derive(... [阅读全文] [PDF]
下面我们再来看看,如果发生虚函数重载的情况。 下图中,我们重载了父类的f()函数。 下面是对于子类实例中的虚函数表的图: 我们可以看见,三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样,我们就可以任一静态类型的父类来指向子类,并调用子类的f()了。如: Derive d; Base1 *b1 = &d; Base2 *b2 = &d; Base3 *b3 = &d; b1->f(); //Derive::f()... [阅读全文] [PDF]
在我那篇《浅析C++中的this指针》中,我通过分析C++代码编译后生成的汇编代码来分析this指针的实现方法。这次我依然用分析C++代码编译后生成的汇编代码来说明C++中虚函数调用的实现方法,顺便也说明一下C++中的对象内部布局。下面所有的汇编代码都是用VC2005编译出来的。虽然,不同的编译器可能会编译出不同的结果,对象的内部布局也不尽相同;但是,只要是符合C++标准的编译器,编译结果和对象的内部布局应该是大同小异。 首先,是一个有着简单继承关系的两个类: class CBase{public:virtual void VFun1() = 0;virtual... [阅读全文] [PDF]
1 共15条 分1页