• c++ 07


    一、多重继承
    1)子类同时拥有两个或两个以上的基类,同时继承了所有基类的属性和行为。
    销售员    经理
            /
        销售经理
    汽车 客用特性 商用特性
           |    /
         公共汽车
    2)内存结构,按照继承表的顺序,从低到高地址一次排列各个基类子对象。将子类对象的地址隐式或者静态转换为基类指针,编译器会做地址计算,以保证基类指针的类型和其所指向的对象一致,但是重解释类型转换(reinterpret_cast)不做此计算。
    3)防止名字冲突。或者由用户程序通过作用域限定解决冲突,或者借助using声明以重载的方式解决冲突,再或者通过汇聚替代,在汇聚子类中提供对产生冲突的函数的隐藏版本,并在该隐藏版本中通过正确的逻辑选择特定基类的实现。
    4)钻石继承问题:公共基类子对象在最终子类对象中存在多个实例,沿着不同的继承路径所访问到的公共基类子对象可能不一样,由此导致数据不一致问题。
         A
        /
       B   C
        /
         D
    为了解决钻石继承问题,需要设法让公共基类子对象在最终子类对象中仅有唯一的实例,且为所有中间子类对象所共享——虚继承。

    二、多态
    形状:位置,绘制
    矩形:宽度、高度,绘制
    圆形:半径,绘制
        Shape
        /  
    Rect     Circle
    如果将基类中的某个成员函数声明为虚函数,那么其子类中与该函数具有相同原型的成员函数就也成为虚函数,并对基类中的版本构成覆盖(override)。通过一个指向子类对象的基类指针,或者引用子类对象的基类引用,调用这个虚函数时,实际被调用的将是子类中的覆盖版本。这种特性被称为多态。

    三、关于覆盖
    1.基类中成员函数必须是虚函数。
    2.子类中成员函数必须与基类中的虚函数拥有完全相同的函数名、形参表和常属性。
    3.如果基类中的虚函数返回基本类型,那么子类覆盖版本的返回类型必须与基类完全相同。如果基类中的虚函数返回类类型的指针或者引用,那么子类覆盖版本的返回类型可以是基类返回类型的子类。
    class X { ... };
    class Y : public X { ... };
    class A {
      virtual int foo (void) { ... }
      virtual X* bar (void) { ... }
    };
    class B : public A {
      int foo (void) { ... }
      Y* bar (void) { ... }
    };
    4.子类中的覆盖版本不能比基类版本抛出更多的异常。
    5.子类中覆盖版本与基类版本的访控属性无关。
    class A {
    public:
      virtual int foo (void) { ... }
    };
    class B : public A {
    private
      int foo (void) { ... }
    };
    B b;
    b.foo (); // ERROR !
    A* p = &b;
    p -> foo (); // OK !

    四、多态=虚函数+指针/引用
    B b;
    A a = (A)b;
    a.foo (); // A::foo()
    class A {
    public:
      void foo (void) {
        this -> bar ();
      }
      virtual void bar (void) {
        cout << 'A' << endl;
      }
    };
    class B : public A {
    private:
      void bar (void) {
        cout << 'B' << endl;
      }
    };
    int main (void) {
      B b;
      b.foo (); // B
    }
    class A {
    public:
      A (void) {
        this -> bar ();
      }
      ~A (void) {
        this -> bar ();
      }
      virtual void bar (void) {
        cout << 'A' << endl;
      }
    };
    class B : public A {
    private:
      void bar (void) {
        cout << 'B' << endl;
      }
    };
    int main (void) {
      B b; // 'A'
    }

    五、虚函数的实现原理——虚函数表
    class A {
    public:
      virtual void foo (void) { ... }
      virtual void bar (void) { ... }
    };
    class B : public A {
    public:
      void foo (void) { ... }
    };
    编译器对于虚函数调用,不会根据调用者的类型生成对特定成员函数调用指令,相反生成一组特殊的指令,该组指令在运行时被执行,完成以下工作:
    1)确定调用对象的真实类型;
    2)从实际调用对象中获取虚函数表指针;
    3)找到与所调用函数相对应的函数地址;
    4)调用该函数。
    ——动态绑定(后期绑定)。
    虚函数与普通成员函数相比,执行开销会更大,虚函数不能做内联优化。

    六、纯虚函数、抽象类和纯抽象类
    形如:
    virtual 返回类型 函数名 (形参表) = 0;
    的虚函数称为纯虚函数。
    至少含有一个纯虚函数的类,称为抽象类。抽象类不能实例化对象。
    除了构造函数和析构函数以外全部由纯虚函数组成类,称为纯抽象类。

    七、运行时类型信息——RTTI
    在运行阶段获得对象的类型信息的方法。
    运算符:typeid
    对象:typeinfo - name()、==、!=
    支持多态。
    dynamic_cast - 在多态父子类指针或引用之间转换。对于指针转换失败返回NULL,对于引用转换失败抛出bad_cast异常。

    八、虚析构函数
    将基类的析构函数定义为虚函数,delete一个指向子类对象的基类指针,实际被执行的就是子类的析构函数,而子类的析构函数又会自动调用基类的析构函数,从而保证子类和基类中所有的资源都被析构干净。

    九、不是所有的函数都能定义为虚函数
    构造函数
    静态函数
    全局函数

    十、模板方法模式
    class PDFReader {
    public:
      void open (const char* file) {
        解析文本;
        this -> drawText ();
        解析矩形;
        drawRect ();
      }
      virtual void drawText (void) = 0;
      virtual void drawRect (void) = 0;
    };
    class PDFRender : public PDFReader {
      void drawText (void) { ... }
      void drawRect (void) { ... }
    };
    PDFRender pr;
    pr.open ("1.pdf");

  • 相关阅读:
    116. Populating Next Right Pointers in Each Node
    117. Populating Next Right Pointers in Each Node II
    经典排序算法总结(含JAVA代码实现)
    Android面试算法篇(java)
    Android单例模式
    Android进阶-Android APK安装过程
    Android进阶-Android性能优化总结
    Android进阶-Android内存泄漏总结
    Android进阶-Android权限处理
    Android进阶-一个APP从启动到主页显示经过了哪些过程?
  • 原文地址:https://www.cnblogs.com/elisha-blogs/p/3780699.html
Copyright © 2020-2023  润新知