| 订阅 | 在线投稿
分享
 
 
 

C++ virtual member function FAQ

2008-06-01 02:25:53 编辑來源:互联网 国际版 评论
 
 
本文为【C++ virtual member function FAQ】的汉字拼音对照版显示拼音
  1 xuchengyuanhanshuhefeixuchengyuanhanshutiaoyongfangshiyoushenmebutong

   feixuchengyuanhanshushijingtaiquedingdeyejiushishuogaichengyuanhanshuzaibianyishibeijingtaidixuanzegaixuanzejiyuzhixiangduixiangdezhizhenhuoyinyongdeleixing xiangbieryanxuchengyuanhanshushidongtaiquedingdezaiyunxingshiyejiushishuochengyuanhanshuzaiyunxingshibeidongtaidixuanzegaixuanzejiyuduixiangdeleixingerbushizhixianggaiduixiangdezhizhen/yinyongdeleixingzhebeichengzuo“dongtaibangding/dongtailianbian”daduoshudebianyiqi使shiyongyixiadeyixiedejishuyejiushisuoweide“VTABLE”jizhi

   bianyiqifaxianyigeleizhongyoubeishengmingweivirtualdehanshujiuhuiweiqigaoyigexuhanshubiaoyejiushiVTABLEVTABLEshijishangshiyigehanshuzhizhendeshuzumeigexuhanshuzhanyongzhegeshuzudeyigeslotyigeleizhiyouyigeVTABLEbuguantayouduoshaogeshilipaishengleiyouzijideVTABLEdanshipaishengleideVTABLEyujileideVTABLEyouxiangtongdehanshupailieshunxutongmingdexuhanshubeifangzailianggeshuzudexiangtongweizhishangzaichuangjianleishilideshihoubianyiqihuanhuizaimeigeshilideneicunbujuzhongzengjiayigevfptrziduangaiziduanzhixiangbenleideVTABLEtongguozhexieshouduanbianyiqizaikandaoyigexuhanshutiaoyongdeshihoujiuhuijiangzhegetiaoyonggaixiezaifenfayigexuhanshushiyunxingshixitonggensuiduixiangde v-pointerzhaodaoleide v-tableranhougensuiv-tablezhongshidangdexiangzhaodaofangfadedaima

   yishangjishudekongjiankaixiaoshicunzaidemeigeduixiangyigeewaidezhizhenjinjinduiyuxuyaodongtaibangdingdeduixiangjiashangmeigefangfayigeewaidezhizhenjinjinduiyuxufangfashijiankaixiaoyeshiyoudeheputonghanshutiaoyongbijiaoxuhanshutiaoyongxuyaolianggeewaidebuzhoudedaov-pointerdezhidedaofangfadedizhiyouyubianyiqizaibianyishijiutongguozhizhenleixingjiejuelefeixuhanshudetiaoyongsuoyizhexiekaixiaobuhuifashengzaifeixuhanshushang

  2 xigouhanshuyekeyishixudeshenzhishichunxudedanshigouzaohanshubunengshixude

   chunxudexigouhanshubingmeiyoushenmezuoyongshixudejiugouletongchangzhiyouzaixiwangjiangyigeleibianchengchouxiangleibunengshilihuadeleierzhegeleiyoumeiyouheshidehanshukeyibeichunxuhuadeshihoukeyi使shiyongchunxudexigouhanshulaidadaomudegouzaohanshubunengshixudeweishenmeyinweizaiyigegouzaohanshutiaoyongqijianxujizhibingbugongzuodanshinikeyikenengtongguoxuhanshu virtual clone()duiyukaobeigouzaohanshuhuoxuhanshu virtual create()duiyumorengouzaohanshudedaoxugouzaohanshuchanshengdexiaoguoruxia

  class Shape {

  public:

   virtual ~Shape() { } // xuxigouhanshu

   virtual void draw() = 0; // chunxuhanshu

   virtual void move() = 0;

   // ...

   virtual Shape* clone() const = 0; // 使shiyongkaobeigouzaohanshu

   virtual Shape* create() const = 0; // 使shiyongmorengouzaohanshu

  };

  class Circle : public Shape {

  public:

   Circle* clone() const { return new Circle(*this); }

   Circle* create() const { return new Circle(); }

   // ...

  };

   zai clone() chengyuanhanshuzhongdaima new Circle(*this) tiaoyong Circle dekaobeigouzaohanshulaifuzhithisdezhuangtaidaoxinchuangjiandeCircleduixiangzai create()chengyuanhanshuzhongdaima new Circle() tiaoyongCircledemorengouzaohanshu

  yonghujiangtamenkanzuo“xugouzaohanshu”lai使shiyongtamen

  void userCode(Shape& s)

  {

   Shape* s2 = s.clone();

   Shape* s3 = s.create();

   // ...

   delete s2; // zaicichunikenengxuyaoxuxigouhanshu

   delete s3;

  }

   zhegehanshujiangzhengquegongzuoerbuguan Shape shiyigeCircleSquarehuoshiqitazhongleide Shapeshenzhitamenhuanbingbucunzai

  

   3 gouzaohanshuhexigouhanshuzhongdexuhanshutiaoyong

   yigeleidexuhanshuzaitazijidegouzaohanshuhexigouhanshuzhongbeitiaoyongdeshihoutamenjiubianchengputonghanshulebu“xu”leyejiushishuobunengzaigouzaohanshuhexigouhanshuzhongrangziji“duotai”liru

  class A

  {

  public:

   A() { foo();} // zaizheliwulunruhedoushiA::foo()beitiaoyong

   ~A() { foo();} // tongshang

   virtual void foo();

  };

  class B: public A

  {

  public:

   virtual void foo();

  };

  void bar()

  {

   A * a = new B;

   delete a;

  }

   jiarunixiwangdelete adeshihouhuidaozhiB::foo()beitiaoyongnamenijiucuoletongyangzainew BdeshihouAdegouzaohanshubeitiaoyongdanshizaiAdegouzaohanshuzhongbeitiaoyongdeshiA::foo()erbushiB::foo()weishenmehuiyouzheyangdeguidingneyuanyinruxia

   dangjileibeigouzaoshiduixianghuanbushiyigepaishengleideduixiangsuoyijiaru Base::Base()tiaoyonglexuhanshu virt()ze Base::virt() jiangbeitiaoyongji使shi Derived::virt()paishengleichongxiegaixuhanshucunzai

   tongyangdangjileibeixigoushiduixiangyijingbuzaishiyigepaishengleiduixianglesuoyijiaru Base::~Base()tiaoyonglevirt()ze Base::virt()dedaokongzhiquanerbushichongxiede Derived::virt()

   dangnikeyixiangxiangdaojiaru Derived::virt() shejidaopaishengleidemougechengyuanduixiangjiangzaochengdezainandeshihounihenkuaijiunengkandaozhezhongfangfademingzhijutilaishuojiaru Base::Base()tiaoyonglexuhanshu virt()zhegeguize使shide Base::virt()beitiaoyongjiarubuanzhaozhegeguizeDerived::virt()jiangzaipaishengduixiangdepaishengbufenbeigouzaozhiqianbeitiaoyongcishishuyupaishengduixiangdepaishengbufendemougechengyuanduixianghuanmeiyoubeigouzaoer Derived::virt()quenenggou访fangwentazhejiangshizainan

  4siyouprivatedexuhanshushifoujuyouduotaixing

   kaolvxiamiandelizi

  class A

  {

  public:

   void foo() { bar();}

  private:

   virtual void bar() { ...}

  };

  class B: public A

  {

  private:

   virtual void bar() { ...}

  };

   zaizhegelizizhongsuiranbar()zaiAleizhongshiprivatededanshirengrankeyichuxianzaipaishengleizhongbingrengrankeyiyupublichuozheprotecteddexuhanshuyiyangchanshengduotaidexiaoguobingbuhuiyinweitashiprivatedejiufashengA::foo()buneng访fangwenB::bar()deqingkuangyebuhuifashengB::bar()duiA::bar()deoverridebuqizuoyongdeqingkuang

   zhezhongxiefadeyuyishiAgaosuBnizuihaooverridewodebar()hanshudanshinibuyaoguantaruhe使shiyongyebuyaozijitiaoyongzhegehanshu原文
 
 
【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 是一个Circle,Square,或是其他种类的 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()函数,但是你不要管它如何使用,也不要自己调用这个函数。
󰈣󰈤
日版宠物情人插曲《Winding Road》歌词

日版宠物情人2017的插曲,很带节奏感,日语的,女生唱的。 最后听见是在第8集的时候女主手割伤了,然后男主用嘴帮她吸了一下,插曲就出来了。 歌手:Def...

兄弟共妻,我成了他们夜里的美食

老钟家的两个儿子很特别,就是跟其他的人不太一样,魔一般的执着。兄弟俩都到了要结婚的年龄了,不管自家老爹怎么磨破嘴皮子,兄弟俩说不娶就不娶,老父母为兄弟两操碎了心...

网络安全治理:国家安全保障的主要方向是打击犯罪,而不是处置和惩罚受害者

来源:中国青年报 新的攻击方法不断涌现,黑客几乎永远占据网络攻击的上风,我们不可能通过技术手段杜绝网络攻击。国家安全保障的主要方向是打击犯罪,而不是处置和惩罚...

 
 
 
>>返回首页<<
 为你推荐
 
 
 
 转载本文
 UBB代码 HTML代码
复制到剪贴板...
 
 
 热帖排行
 
单纯美女 迷人女孩
校园甜美少女
忍辱负重
大学校园
 
 
王朝网络微信公众号
微信扫码关注本站公众号wangchaonetcn
 
  免责声明:本文仅代表作者个人观点,与王朝网络无关。王朝网络登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
©2005- 王朝网络 版权所有