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: 函数名(参数列表)

 

原文地址:https://www.cnblogs.com/youxin/p/2566266.html