动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
电脑书籍下载:程序设计书籍 | 数据库教程书籍 | 平面与多媒体书籍 | 网络通讯书籍 | 系统管理书籍 | 网络安全书籍 | 认证考试书籍
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > 软件工程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ 软件工程 ]的信息



本月文章推荐
.“实现能力”与“设计能力”.
.解析.NET框架下的数据类型转化技.
.IBM发布11项新品 加速实现SOA.
.汉化软件的测试综述.
.添加聪明角色 让网页动起来.
.3DS模型Bump Map(凹凸贴图)渲染.
.构建下一代软件架构SOA.
.客户关系管理的三大纪律.
.入侵检测技术综之不可忽视的社会.
.软件项目质量管理.
.IDS逃避技术和对策的详细介绍.
.Apache中的挂钩剖析(1).
.关于项目团队的发展阶段特点、问.
.ESB在SOA内的工作角色分析.
.小型软件的通用界面设计制作指南.
.微软事务处理服务介绍.
.SOA:构建更好的企业应用架构.
.基于VS.NET的自定项目模板研究.
.使用UML设计数据库应用(1).
.IBM 建立商业解决方案中心.

C++ virtual member function FAQ

发表日期:2008-3-23 |


【1】  虚成员函数和非虚成员函数调用方式有什么不同?
    非虚成员函数是静态确定的。也就是说,该成员函数(在编译时)被静态地选择,该选择基于指向对象的指针(或引用)的类型。 相比而言,虚成员函数是动态确定的(在运行时)。也就是说,成员函数(在运行时)被动态地选择,该选择基于对象的类型,而不是指向该对象的指针/引用的类型。这被称作“动态绑定/动态联编”。大多数的编译器使用以下的一些的技术,也就是所谓的“VTABLE”机制:
     编译器发现一个类中有被声明为virtual的函数,就会为其搞一个虚函数表,也就是VTABLE。VTABLE实际上是一个函数指针的数组,每个虚函数占用这个数组的一个slot。一个类只有一个VTABLE,不管它有多少个实例。派生类有自己的VTABLE,但是派生类的VTABLE与基类的VTABLE有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。在创建类实例的时候,编译器还会在每个实例的内存布局中增加一个vfptr字段,该字段指向本类的VTABLE。通过这些手段,编译器在看到一个虚函数调用的时候,就会将这个调用改写,在分发一个虚函数时,运行时系统跟随对象的 v-pointer找到类的 v-table,然后跟随v-table中适当的项找到方法的代码。
    以上技术的空间开销是存在的:每个对象一个额外的指针(仅仅对于需要动态绑定的对象),加上每个方法一个额外的指针(仅仅对于虚方法)。时间开销也是有的:和普通函数调用比较,虚函数调用需要两个额外的步骤(得到v-pointer的值,得到方法的地址)。由于编译器在编译时就通过指针类型解决了非虚函数的调用,所以这些开销不会发生在非虚函数上。 【2】 析构函数也可以是虚的,甚至是纯虚的,但是构造函数不能是虚的
     纯虚的析构函数并没有什么作用,是虚的就够了。通常只有在希望将一个类变成抽象类(不能实例化的类),而这个类又没有合适的函数可以被纯虚化的时候,可以使用纯虚的析构函数来达到目的。构造函数不能是虚的(为什么?因为在一个构造函数调用期间,虚机制并不工作),但是你可以可能通过虚函数 virtual clone()(对于拷贝构造函数)或虚函数 virtual create()(对于默认构造函数),得到虚构造函数产生的效果。如下:
class Shape {
 public:
   virtual ~Shape() { }                 // 虚析构函数
   virtual void draw() = 0;             
// 纯虚函数
   virtual void move() = 0;
   
// ...
   virtual Shape* clone()  const = 0;   
// 使用拷贝构造函数
   virtual Shape* create() const = 0;   
// 使用默认构造函数
 };
 
 class Circle : public Shape {
 public:
   Circle* clone()  const { return new Circle(*this); }
   Circle* create() const { return new Circle();      }
   
// ...
 };
    在 clone() 成员函数中,代码 new Circle(*this) 调用 Circle 的拷贝构造函数来复制this的状态到新创建的Circle对象。在 create()成员函数中,代码 new Circle() 调用Circle的默认构造函数。
用户将它们看作“虚构造函数”来使用它们:
 void userCode(Shape& s)
 {
   Shape* s2 = s.clone();
   Shape* s3 = s.create();
   
// ...
   delete s2;    
// 在此处,你可能需要虚析构函数
   delete s3;
 }
    这个函数将正确工作,而不管 Shape 是一个CircleSquare,或是其他种类的 Shape,甚至它们还并不存在。
【3】 构造函数和析构函数中的虚函数调用
    一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们就变成普通函数了,不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。例如:
class A
{
public:
    A() { foo();}        // 在这里,无论如何都是A::foo()被调用!
    ~A() { foo();}       // 同上
    virtual void foo();
};

class B: public A
{
public:
    virtual void foo();
};

void bar()
{
    A * a = new B;
    delete a;
}
    假如你希望delete a的时候,会导致B::foo()被调用,那么你就错了。同样,在new B的时候,A的构造函数被调用,但是在A的构造函数中,被调用的是A::foo()而不是B::foo()。为什么会有这样的规定呢,原因如下:
    当基类被构造时,对象还不是一个派生类的对象,所以假如 Base::Base()调用了虚函数 virt(),则 Base::virt() 将被调用,即使 Derived::virt()(派生类重写该虚函数)存在。
    同样,当基类被析构时,对象已经不再是一个派生类对象了,所以假如 Base::~Base()调用了virt(),则 Base::virt()得到控制权,而不是重写的 Derived::virt()
    当你可以想象到假如 Derived::virt() 涉及到派生类的某个成员对象将造成的灾难的时候,你很快就能看到这种方法的明智。具体来说,假如 Base::Base()调用了虚函数 virt(),这个规则使得 Base::virt()被调用。假如不按照这个规则,Derived::virt()将在派生对象的派生部分被构造之前被调用,此时属于派生对象的派生部分的某个成员对象还没有被构造,而 Derived::virt()却能够访问它。这将是灾难。 【4】私有private的虚函数是否具有多态性
    考虑下面的例子:
class A
{
public:
    void foo() { bar();}
private:
    virtual void bar() { ...}
}; class B: public A
{
private:
    virtual void bar() { ...}
};
    在这个例子中,虽然bar()在A类中是private的,但是仍然可以出现在派生类中,并仍然可以与public或者protected的虚函数一样产生多态的效果。并不会因为它是private的,就发生A::foo()不能访问B::bar()的情况,也不会发生B::bar()对A::bar()的override不起作用的情况。
    这种写法的语意是:A告诉B,你最好override我的bar()函数,但是你不要管它如何使用,也不要自己调用这个函数。
上一篇:项目管理中需要处理好的四个问题 人气:185
下一篇:使用python写的代码行数统计程序 人气:309
浏览全部软件工程的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-7-25 WikyBlog v1.7.0.1 多国语言版
2008-7-25 乐彼网上开店系统(56770 Eshop)
2008-7-25 赛特网站管理系统sitecms v3.6.0
2008-7-25 Modoer多功能点评系统 v1.0.1 Bu
2008-7-25 Shangducms Teamsuit! v1.1.0 开
2008-7-25 幻影动漫网视频系统(Ppdong) v1.
2008-7-25 acteecompany企业网站建设系统 v
2008-7-25 恒浪整合管理系统 ims v4.1 ACCE
2008-7-25 艺术图库系统 v1.0 beta
2008-7-19 UltraEdit 简体中文增强版 14.10
2008-7-19 CentOS 5.2 i386 LiveCD
2008-7-19 Snapture多功能相机 v1.4
2008-7-19 iAcces中文输入法 v1.0Build016
2008-7-19 Cookbook烹饪秘籍 v2.5
2008-7-19 苹果专用DVD转换工具 v1.1.59汉化
2008-7-19 Modem修复软件ZiPhone修改版04.0
2008-7-19 AgileMessenger即时通讯工具美化
2008-7-19 Sketches画图软件 v0.7b6破解版


  发表评论
姓 名: 验证码:
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵