• C++ 继承、派生、多态


    继承就是在一个已存在的类的基础上建立一个新的类。

    已存在的类称为基类,又称父类;新建立类称为派生类,又称为子类

    继承允许我们依据另一个类来定义一个类,不需要重新编写一部分的数据成员和成员函数,达到了重用代码功能和提高执行效率的效果。

    基类与派生类

    一个类可以派生自多个类,从多个基类继承数据和函数。我们使用一个类派生列表来指定基类。

    class derived-class: access-specifier base-class
    

    其中,访问修饰符 access-specifierpublicprotectedprivate 其中的一个,如果未指定则默认 private

    搬运一个例子

    class Shape {
    public:
        void setWidth(int w) {
            width = w;
        }
        void setHeight(int h) {
            height = h;
        }
    protected:
        int width;
        int height;
    };
    class Rectangle: public Shape {
    public:
        int getArea() {
            return (width * height);
        }
    };
    int main(void) {
        Rectangle Rect;
        Rect.setWidth(5);
        Rect.setHeight(7);
        cout << "Total area: " << Rect.getArea() << endl;
    }
    
    

    派生类继承了基类的属性,继承了基类的行为,可以添加额外的行为,也可以重新定义这些行为。

    若基类定义的数据成员和派生类添加的数据成员同名,基类数据成员被覆盖。注意,即使函数名相同,参数不同,也无法调用基类函数。

    在访问时,句柄的类型决定哪个类的成员被访问。使用对象名或引用访问同名成员,根据引用的类型决定,使用基类指针访问同名的成员,根据指针类型决定。

    访问控制

    派生类可以访问基类中所有的非私有成员。一个派生类继承了除去构造函数、析构函数、重载运算符、友元函数以外所有的基类方法.

    不同继承类型的规则如下

    • 公有继承(public):
      • 基类的公有成员也是派生类的公有成员
      • 基类的保护成员也是派生类的保护成员
      • 基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有保护成员来访问。
    • 保护继承(protected):
      • 基类的公有保护成员将成为派生类的保护成员。
    • 私有继承(private):
      • 基类的公有保护成员将成为派生类的私有成员。

    基类的友元函数可以访问基类中的私有成员,以及派生类从基类中继承的成员。派生类中的友元函数只能访问派生类的私有成员,而不能访问基类中的私有成员。

    拷贝构造函数仅用于同类拷贝或派生类向基类拷贝,而不能用于基类向派生类拷贝。

    虚拟与多态

    虚函数与纯虚函数

    定义虚函数是为了允许用基类的指针来调用子类的这个函数。

    例如以下程序的输出结果为 B

    class A {
    public:
        virtual void foo() {
            cout<<"A"<<endl;
        }
    };
    class B:public A {
    public:
        void foo() {
            cout<<"B"<<endl;
        }
    };
    int main() {
        A *a = new B();
        a->foo();
    }
    
    

    在这里,调用的是哪个函数不是在编译时刻被确定的,而是在运行时刻被确定的。换言之,在编译时,并不知道被调用的是基类的函数还是哪个派生类的函数。

    定义一个函数为纯虚函数,代表函数没有被实现,只是为了实现一个接口。它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。定义方式为

    virtual void func()=0;
    

    多态

    在面向对象语言中,接口的多种不同的实现方式即为多态。

    类的多态允许将子类类型的指针赋值给父类类型的指针。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

    从应用的角度说,在基类的函数前加上 virtual 关键字声明为虚函数后,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。

    所有虚类的对象里面会自动加上一个隐藏指针,指向一张属于类的表 vtable,里是所有 virtual 函数的地址。

    带有虚函数的类

    每一个类都有虚表,且虚表可以继承。

    如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。

    如果重写了相应的虚函数,那么虚表中的地址就会改变,指向自身的虚函数实现。

    如果派生类有自己的虚函数,那么虚表中就会添加该项。

    所谓类的多态性,即将基类的函数定义为虚函数,在派生类中重写,运行时将会根据对象的实际类型来调用相应的函数。

    注意区分类的多态性与函数的多态性。函数的多态性指一个函数被定义成多个不同参数的函数,调用这个函数时,就会调用不同的同名函数。

    总结

    派生类继承自基础类,可以描述基类对象集合中一组更细化、特殊的对象。派生类继承了基类的属性,继承了基类的行为,可以添加额外的行为,也可以重新定义这些行为。

    虚函数是为了允许用基类的指针来调用子类的这个函数。调用的是哪个函数不是在编译时刻被确定的,而是在运行时刻被确定的。

    定义一个函数为纯虚函数,代表函数没有被实现,只是为了实现一个接口。它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。

    类的多态允许将子类类型的指针赋值给父类类型的指针。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

  • 相关阅读:
    spring 循环依赖问题
    spring data jpa 关键字 命名
    mongodb 添加字段并设置默认值
    java mongoTemplate的group统计
    java8 从对象集合中取出某个字段的集合
    springboot12-zuul
    springboot11-01-security入门
    springboot项目怎么部署到外部tomcat
    springboot10-springcloud-eureka 服务注册与发现,负载均衡客户端(ribbon,feign)调用
    UML
  • 原文地址:https://www.cnblogs.com/mollnn/p/12612713.html
Copyright © 2020-2023  润新知