美文网首页
C++ 编程技巧与规范(三)

C++ 编程技巧与规范(三)

作者: e196efe3d7df | 来源:发表于2020-11-20 14:33 被阅读0次

    类的public继承(is-a关系)及代码编写规范

    子类继承父类的方式有三种:public, protected, private
    其中public继承表示的是is-a(is a kind of)关系。表示:通过子类产生的对象也一定是一个父类对象。能在父类上表现的行为,也必然能在子类上表现。父类出现的地方,必然能用子类来替换(里氏替换原则(LSP))。
    父类表示一种更泛化的概念,子类表示一种更特化的概念

    子类遮蔽父类的普通成员函数

    如果父类和子类中有相同函数签名的普通成员函数,则子类中的函数会遮蔽掉父类中的函数。如下:

    namespace demo5 {
        class Human {
        public:
            virtual ~Human() {};
            void eat() {
                std::cout << "人类吃" << std::endl;
            }
        };
    
        class Man :public Human {
        public:
            void eat() {
                std::cout << "男人吃" << std::endl;
            }
        };
    
        void mainFunc() {
            Man man;
            man.eat();          //父类的eat被子类遮蔽,调用的的是子类的eat
            man.Human::eat();   //强制调用父类被遮蔽的函数
        }
    }
    
    int main()
    {
        demo5::mainFunc();
    }
    

    运行结果如下:


    注:对于public继承,不建议也不应该让子类遮蔽父类的普通成员函数。既然在父类中是普通成员函数,则代表在子类中不会有不同行为。

    父类的纯虚函数接口

    纯虚函数的表现如下:

    1. 纯虚函数没有函数体,没有行为,需要子类定义具体行为。
    2. 纯虚函数就是interface,需要子类必须实现。
    3. 纯虚函数所在的类就是抽象类,不能生成该类的对象。
    namespace demo5 {
        class Human {
        public:
            virtual ~Human() {};
        public:
            virtual void work() = 0;
            void eat() {
                std::cout << "人类吃" << std::endl;
            }
        };
    
        class Man : public Human {
        public:
            virtual void work() {
                std::cout << "重体力活" << std::endl;
            }
        };
    
        class Woman : public Human {
        public:
            virtual void work() {
                std::cout << "轻体力活" << std::endl;
            }
        };
    
        void mainFunc2() {
            Woman woman;
            woman.work();
        }
    }
    
    int main()
    {
        demo5::mainFunc2();
    }
    

    父类的虚函数接口

    虚函数接口,让子类继承父类的成员函数的接口及实现,表现如下:

    1. 子类可以提供自己的新实现。
    2. 子类不提供自己的实现,则会使用父类的实现
    3. 可以同时使用子类和父类的实现。
    namespace demo6 {
        class Human {
        public:
            virtual ~Human() {};
        public:
            virtual void avlf() {
                std::cout << "人类75岁" << std::endl;
            }
        };
    
        class Man : public Human {
        public:
            virtual void avlf() {
                std::cout << "男人70岁" << std::endl;
            }
        };
    
        class Woman : public Human {
        public:
            virtual void avlf() {
                //调用父类
                Human::avlf();
                //子类自身的实现
                std::cout << "女人80岁" << std::endl;  
            }
        };
    
        void mainFunc() {
            Woman woman;
            Man man;
            woman.avlf();
            man.avlf();
        }
    }
    
    int main()
    {
        demo6::mainFunc();
    }
    

    为纯虚函数制定实现体

    有这样一种需求:

    1. 强制让子类实现该函数。
    2. 需要一些公共行为放在父类的该函数中。

    也就是结合纯虚函数和虚函数的功能。是不是有些骚?其实是可以实现。纯虚函数也可以有自己的函数体:

    namespace demo7 {
        class Human {
        public:
            virtual ~Human() {};
        public:
            virtual void work() = 0;
        };
    
        void Human::work()
        {
            std::cout << "人类干活" << std::endl;
        }
    
        class Man : public Human {
        public:
            virtual void work()
            {
                Human::work();
                std::cout << "男人:重体力活" << std::endl;
            }
        };
    
        class Woman : public Human {
        public:
            virtual void work()
            {
                Human::work();
                std::cout << "女人:轻体力活" << std::endl;
            }
        };
    
        void mainFunc() {
            Woman woman;
            Man man;
            woman.work();
            man.work();
        }
    }
    
    int main()
    {
        demo7::mainFunc();
    }
    

    运行结果如下:


    类的public继承综合范例

    --省略了

    public继承关系下的代码编写规范

    综上:

    1. 父类的普通成员函数,子类不应该去覆盖。如果需要覆盖,则需要在父类中将该普通成员函数修改为虚函数。
    2. 父类的纯虚函数,实际就是一个接口,子类必须要去实现该接口。且包含纯虚函数的父类为抽象类,不能实例化。
    3. 父类的普通虚函数(非纯虚函数),不但定义一个接口,而且还允许有自己的实现。子类可以继承该实现,也可以覆盖该实现,也会混用该实现
    4. 非必要使用public继承时,就不要使用public继承,必须要满足is-a关系。

    类的private继承

    private继承,不是is-a关系,是一种组合关系。确切的说是组合关系中的is-implemented-in-terms-of关系(根据...实现出...)。
    一般优先考虑使用普通的组合关系,只有一些特殊情况和必要情况下,比如一些protected成员,private成员,虚函数等时才考虑使用private继承,来表示这种组合关系。

    相关文章

      网友评论

          本文标题:C++ 编程技巧与规范(三)

          本文链接:https://www.haomeiwen.com/subject/pwcliktx.html