zoukankan      html  css  js  c++  java
  • C++进阶--类的继承

    //############################################################################
    /*
     * 公有,保护,私有继承
     */
    
    class B { 
    };
    class D_priv : private   B { };        //私有继承
    class D_prot : protected B { };     //保护继承
    class D_pub : public    B { };        //公有继承
    
    
    /*
    不同的继承方法指定了派生类对基类不同的访问控制权限
    
    上述三个派生类:
    1. 都不能访问B中的私有成员. 
    2. D_pub继承B中的公有成员为公有,继承B中的保护成员为保护
    3. D_priv继承B中的公有保护成员为私有
    4. D_prot继承B中的公有保护成员为保护
    
    转换:
    1. 任何人都可以将一个D_pub*转换为B*. D_pub是B的特殊情况
    2. D_priv的成员和友元可以将D_priv*转成B*
    3. D_prot的成员,友元及子女可以将D_prot*转成B*
    
    注意:只有公有继承是is-a的关系
    */
    
    /* 详细实例 */
    
    class B { 
       public:
          void f_pub() { cout << "f_pub is called.
    "; }
       protected:
          void f_prot() { cout << "f_prot is called.
    "; }
       private:
          void f_priv() { cout << "f_priv is called.
    "; }
    };
    
    class D_pub : public B {  //对于公有继承
       public:
          void f() { 
             f_pub();   // OK. D_pub的公有成员函数
             f_prot();  // OK. D_pub的保护成员函数
             f_priv();  // Error. B的私有成员函数 
          }
    };
    
    class D_priv : private   B { //对于私有继承
       public:
       using B::f_pub; //使其在D_priv的作用域内可见
          void f() {
             f_pub();   // OK. D_priv的私有成员函数
             f_prot();  // OK. D_priv 的私有成员函数
             f_priv();  // Error. B的私有成员函数 
          }
    };
    
    int main() {
       D_pub D1;
       D1.f_pub();  // OK. f_pub()是D_pub的公有成员函数
    
       D_priv D2;
       D2.f_pub();  // Error. f_pub()是D_priv的私有成员函数,增加using B::f_pub之后OK
    
       B* pB = &D1;  // OK  可以转换
       pB = &D2;     // Error  不能转换
       ...
    }
    
    //############################################################################
    /*
     * 私有继承: 类似于has-a关系,跟组合类似
     */
    class Ring {
       virtual tremble();
       public:
       void tinkle() {...; tremble(); }
    };
    
    /* 组合 */
    class Dog {
       Ring m_ring;
       public:
       void tinkle() {m_ring.tinkle();}  // 向前调用
    };
    
    
    /* 私有继承*/
    class Dog_Priv : private Ring {
       public:
       using Ring::tinkle;
    };
    
    /*
     * 组合的优点: 比如可以有多个ring,ring可以切换 //通常情况下倾向于组合,更低耦合,更灵活
     * 私有继承的优点:更优雅的多态,比如
     *
     * 在ring类中增加虚函数tremble(), 该函数在tinkle中被调用
     */
    
    
    
    /*
     * 公有继承 => "is-a" 关系
     *
     * 基类能做的任何事情,派生类需要也能做
     */
    
    //像以下类的设计就是不合适的
    class Bird { 
       public:
       void fly();
    };
    
    class Penguin : public Bird {};
    
    Penguin p;
    p.fly();
    
    
    // class flyableBird : public bird {};
    //   public:
    //      void fly();
    //penguin p;
    //p.fly();
    
    
    // 看几个例子
    class Dog {
       public:
          void bark() { cout << "Whoof, I am just a dog.
    ";};
    };
    
    class Yellowdog : public Dog{
       public:
          void bark() { cout << "Whoof, I am a yellow dog.
    ";};
    };
    
    int main() {
       Yellowdog* py = new Yellowdog();
       py->bark(); 
       Dog* pd = py;
       pd->bark(); 
    }
    
    OUTPUT:
    Whoof, I am a yellow dog.
    Whoof, I am just a dog.
    /*
     * 结论:不要覆写非虚函数
     */
    
    
    class Dog {
       public:
       void bark(int age) { cout << "I am " << age; }
       virtual void bark(string msg = "just a" ) { 
          cout << "Whoof, I am " << msg << " dog." << endl; }
    };
    
    class Yellowdog : public Dog {
       public:
       using Dog::bark;
       virtual void bark(string msg="a yellow" ) { 
          cout << "Whoof, I am " << msg << " dog." << endl; }
    };
    
    int main() {
       Yellowdog* py = new Yellowdog();
       py->bark(5); 
    }
    
    OUTPUT:
    Whoof, I am a yellow dog.
    Whoof, I am just a dog.
    
    /*
     * 不要重新定义虚函数的默认参数
     *   - 默认参数是静态绑定的
     *   - 虚函数是动态绑定的
     */
    
    
    /*
     * 在类dog中增加如下函数:
     * virtual void bark(int age) { cout << "I am " << age << " years old"<< endl; }
     * in main(),
     *    py->bark(5);  // 编译不过
     *                  // 可以通过在yellowdog中加"using Dog::bark;"修复  为了保持is-a关系
     */
    
    
    // 防止意外覆写,或者没有覆写,增加了override关键字
    class Dog {
       public:
          virtual void bark() { cout << "I am just a dog.
    ";};
          void run();
    };
    
    class Yellowdog : public Dog{
       public:
          virtual void barks() { cout << "I am a yellow dog.
    ";}; //在旧标准中不会报错,等出错了调试比较困难
    };
    
    
    // C++ 11 standard:
    class Yellowdog : public Dog{
       public:
          virtual void barks() override;       
                // 编译错误:没有覆写的函数
    
          virtual void bark() const override;  
                // 编译错误:没有覆写的函数
    
          void run() override;  // 压根不是虚函数,错误
    };
    
    
    /* 
     * 避免采坑:
     * 1. 类的精确定义
     * 2. 不要覆写非虚函数
     * 3. 不要覆写虚函数的默认参数
     * 4. 强制继承被遮盖的函数
     * 5. 小心函数覆写时的错字
     */
    
  • 相关阅读:
    安装mongodb,开启mongo服务,创建mongodb用户,登陆mongodb
    【Flask】bootstrap table基础
    【网络安全】加解密算法最详解
    UAC table
    Docker的部署安装(CentOS)-by paymob
    Docker中运行MySQL5.7并挂载宿主机目录到镜像
    搭建harbor企业级私有registry
    Rancher的部署安装(编排选用K8S)
    使用Rancher pipeline搭建基于容器的CICD
    Docker的部署安装(CentOS)
  • 原文地址:https://www.cnblogs.com/logchen/p/10171771.html
Copyright © 2011-2022 走看看