• c++ 很多相关概念


    下面的一个简单的继承:

    #include<iostream>
    using namespace std;
    
    class Animal
    {
    public:
        Animal(int height,int weight)
        {
            cout<<"animal construct"<<endl;
    
        }
        ~Animal()
        {
            cout<<"animal destruct"<<endl;
        }
    };
    
    class Fish:public Animal
    {
    public:
        Fish()
        {
            cout<<"fish construct"<<endl;
        }
        ~Fish()
        {
            cout<<"fish destruct"<<endl;
        }
    };
    
    int main()
    {
      Fish fh;
    }

    上面的编译不通过,没有适合的构造函数 。'Animal' : no appropriate default constructor available??

     因为:当构造Fish 的fh对象时,需要先Animal对象。调用Animal默认的构造函数,而在我们的程序中,只有一个带有参数的构造函数,因此,找不到构造函数而错误。

    因此,构造fish时,要想办法调用Animal带参的构造函数。显示地调用.改为:

        Fish():Animal(300,500)

    派生类转换为基类

    #include<iostream>
    using namespace std;
    
    class Animal
    {
    public:
        Animal(int height,int weight)
        {
            cout<<"animal construct"<<endl;
    
        }
        ~Animal()
        {
            cout<<"animal destruct"<<endl;
        }
    
        void breath()
        {
            cout<<"animal breath"<<endl;
        }
    };
    
    class Fish:public Animal
    {
    public:
        Fish():Animal(300,500)
        {
            cout<<"fish construct"<<endl;
        }
        ~Fish()
        {
            cout<<"fish destruct"<<endl;
        }
    
        void breath()
        {
            cout<<"fish breath"<<endl;
        }
    
    };
    
    void func(Animal *p)
    {
        p->breath();
    }
    
    int main()
    {
      Fish fh;
      Animal *pAn;
      pAn=&fh;
      func(pAn);
    
    }

    会输出animal breath;

    因为fish 对象地址赋给pAn时,c++编译器进行了类型转换。此时编译器就认为pAn保存的就是Animal对象的地址。在func函数中调用breath时,当然就认为是Animal的breath();

        当我们构造fish类的对象时,首先要调用animal类的构造函数去构造animal类的对象。然后才调用fish类的构造函数完成自身部分的构造,从而拼接出一个完整的fish对象。我们将fish类的对象转换为aniaml类型是,该对象就认为是原对象整个内存模型的上半部分,也就是图中animal的对象所占的内存,当我们利用类型转换后的 对象指针去调用它的方法时,自然就是
    调用它所在内存的方法。

    如果想在上面的代码中输出fish breath,只需改一句代码:

    void breath();改为

      virtual  void breath()

    virtual函数采用late binding技术,也就是编译时并不确定具体调用的函数,而是在运行时,依据对象的类型(在程序中,我们传递的fish类对象的地址)来确认调用的是 哪一个函数,这种能力就叫做c++的多态性

    纯虚函数

      将breath函数定义为纯虚函数,在函数定义加上=0

    class Animal
    {
    public:
        Animal(int height,int weight)
        {
            cout<<"animal construct"<<endl;
    
        }
        ~Animal()
        {
            cout<<"animal destruct"<<endl;
        }
        virtual    void breath()=0;
    };

    含有纯虚函数的类叫做抽象类抽象类不能构造对象。抽象类为派生类服务。在派生类中必须完全实现基类的纯虚函数,否则,派生类也就变成了抽象类,不能实例化对象

    函数的覆盖

    class Animal
    {
    public:
        ..
        virtual void breath()
        {
            cout<<"animal breath"<<endl;
        }
    };
    class Fish:public animal
    {
    public:
        void breath()
        {
            cout<<"fish breath:"<<endl;
        }
    };

       fish类的breath函数和 animal类的breath函数完全一样,无论函数名,还是参数列表都是一样的,这称为函数的覆盖(override)。

    构成函数覆盖的条件:
    1.基类函数必须是虚函数(使用virtual声明)
    2.发生覆盖的两个函数要分别位于派生类和基类中
    3函数名称和参数列表必须完全相同

    函数的隐藏

    class Animal
    {
    public:
        ..
         void breath()
        {
            cout<<"animal breath"<<endl;
        }
    };
    class Fish:public animal
    {
    public:
        void breath()
        {
            cout<<"fish breath:"<<endl;
        }
    };

    派生类fish中的breath函数和基类animal中的breath函数也是完全一样的。不同的是breath函数不是虚函数。这种情况
    称为函数的隐藏。所谓隐藏,是指派生类中具有与基类同名的函数(不考虑参数列表是否相同),从而在派生类中隐藏了基类的同名函数。

     当发生隐藏时,想要在派生类中 使用基类的函数时:

     BaseClass: 函数名(参数列表)

     

  • 相关阅读:
    javascript延迟对象
    Fetch-新一代Ajax API
    AJAX笔记
    VR/AR/MR
    为什么Javascript有设计缺陷
    Javascript函数式编程
    vim基本操作
    Git 常用命令(二)
    SSH配置
    C# NPOI导出Excel和EPPlus导出Excel
  • 原文地址:https://www.cnblogs.com/youxin/p/2566266.html
Copyright © 2020-2023  润新知