C++笔记:面向对象编程(Visual)(二)

2014-11-24 11:23:59 · 作者: · 浏览: 1
ize_t) const = 0;


虚继承

  • 虚继承是一种机制,类通过虚继承指出它希望共享其虚基类的状态。在虚继承下,对给定虚基类,无论该类在派生层次中作为虚基类出现多少次,只继承一个共享的基类子对象。共享的基类子对象称为虚基类。[Code5]
  • 指定虚派生只影响从指定了虚基类的类派生的类。除了影响派生类自己的对象之外,它也是关于派生类与自己的未来派生类的关系的一个陈述。
  • 任何可被指定为基类的类也可以被指定为虚基类,虚基类可以包含通常由非虚基类支持的任意类元素。虚继承支持到基类到常规转换。
  • 使用虚基类的多重继承层次比没有虚继承的引起更少的二义性问题
  • 虚基类成员的可见性,假定通过多个派生路径继承名为 X 的成员
    • 如果在每个路径中 X 表示同一虚基类成员,则没有二义性,因为共享该成员的单个实例。
    • 如果在某个路径中 X 是虚基类的成员,而在另一路径中 X 是后代派生类的成员,也没有二义性――特定派生类实例的优先级高于共享虚基类实例。
    • 如果沿每个继承路径 X 表示后代派生类的不同成员,则该成员的直接访问是二义性的。

      Code

      Code1:覆盖虚函数机制

      Item_base *baseP = &derived;
       //calls version from the base class regardless of the dynamic type of baseP
       double d = baseP->Item_base::net_price(42);

      Code2:虚析构函数

      /*如果析构函数为虚函数,那么通过指针调用时,运行哪个析构函数将因指针所指对象类型的不同而不同:*/
      Item_base *itemP = new Item_base; // same static and dynamic type 
      delete itemP; // ok: destructor for Item_base called 
      itemP = new Bulk_item; // ok: static and dynamic types differ 
      delete itemP; // ok: destructor for Bulk_item called
      

      Code3:虚函数必须在基类和派生类中拥有同一原型

      class Base {
       public:
           virtual int fcn();
       };
       class D1 : public Base {
       public:
            // hides fcn in the base; this fcn is not virtual
            int fcn(int); // parameter list differs from fcn in Base
       // D1 inherits definition of Base::fcn()
       };
       class D2 : public D1 {
       public:
           int fcn(int); // nonvirtual function hides D1::fcn(int)
           int fcn();    // redefines virtual fcn from Base
       };
      /*D1 中的 fcn 版本没有重定义 Base 的虚函数 fcn,相反,它屏蔽了基类的 fcn。结果 D1 有两个名   为 fcn 的函数:类从 Base 继承了一个名为 fcn 的虚 函数,类又定义了自己的名为 fcn 的非虚成员函   数,该函数接受一个 int 形参。 但是,从 Base 继承的虚函数不能通过 D1 对象(或 D1 的引用或指针) 调用, 因为该函数被 fcn(int) 的定义屏蔽了。
      类 D2 重定义了它继承的两个函数,它重定义了 Base 中定义的 fcn 的原始版本并重定义了 D1 中定义 的非虚版本。*/

      Code4:通过基类调用被屏蔽的虚函数

      Base bobj;  D1 d1obj;  D2 d2obj;
      Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
      bp1->fcn();
      bp2->fcn();
      bp3->fcn();
      // ok: virtual call, will call Base::fcnat run time // ok: virtual call, will   call Base::fcnat run time // ok: virtual call, will call D2::fcnat run time
      三个指针都是基类类型的指针,因此通过在 Base 中查找 fcn 来确定这三 个调用,所以这些调用是合法    的。另外,因为 fcn 是虚函数,所以编译器会生成代码,在运行时基于引用指针所绑定的对象的实际类型进    行调用。在 bp2 的情况,基本对象是 D1 类的,D1 类没有重定义不接受实参的虚函数版本,通过 bp2 的 函数调用(在运行时)调用 Base 中定义的版本。

      Code5:虚继承

      /*每个 IO 库类都继承了一个共同的抽象基类,那个抽象基类管理流的条件状态并保存流所读写的缓冲区。    istream 和 ostream 类直接继承这个公共基类,库定义了另一个名为 iostream 的类,它同时继承   istream 和 ostream,iostream 类既可以对流进行读又可以对流进行写。
      我们知道,多重继承的类从它的每个父类继承状态和动作,如果 IO 类 型使用常规继承,则每个 iostream    对象可能包含两个 ios 子对象:一个包含 在它的 istream 子对象中,另一个包含在它的 ostream 子对  象中,从设计角度讲,这个实现正是错误的:iostream 类想要对单个缓冲区进行读和写,它希望跨越输入和输   出操作符共享条件状态。如果有两个单独的 ios 对象,这种共享是不可能的。
      在 C++ 中,通过使用虚继承解决这类问题。*/
      class istream : public virtual ios { ... };
      class ostream : virtual public ios { ... };
      // iostream inherits only one copy of its ios base class
      class iostream: public istream, public ostream { ... };
      

      From:
      http://blog.csdn.net/liufei_learning/article/details/22708639