多态中特例

1:协变

定义:
派生类重写基类时,两个虚函数的返回值类型不同,基类返回的是基类对象的**指针或者引用,**派生类返回派生类对象的指针或者引用,就称为发生了协变。我们认为协变是一种多态的特例

我们来看一组程序

using namespace std;
class Base
{
public:
	Base()
	{
		cout << "Base" << endl;
	}
	virtual void fun()
	{
		cout << "Base" << endl;
	}
	virtual Base* Test()
	{
		cout << "Base()" << endl;
		return this;
	}
private:
	int m_a;
	int m_b;
};

class A :public Base
{
public:
	A()
	{
		cout << "A" << endl;
	}
	void fun()
	{
		cout << "A" << endl;
	}
	A * Test()
	{
		cout << "A()" << endl;
		return this;
	}
private:
	int a;
	int b;
};

int main()
{
	A a;
	Base *p = &a;
	p->Test();
	system("pause");
	return 0;
}

本身这个Test()是不满足多态的,因为返回值是不一样的,不满足我们重写的三同(返回值,函数名,形参),按理说是不能调动子类方法的,但是这里是可以调用子类方法的,就称为协变。
在这里插入图片描述

2:析构函数重写

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同,但是依旧可以重写。可以理解成编译器对这个名字做了优化处理,编译后析构函数的名称统一处理成destructor。

这个时候我们就想,我为什么要重写析构函数?
如果我们在堆上申请一个类


class Base
{
  public:
      void fun()
      {
            cout << "Base" << endl;
              
      }
      Base()
      {
        cout<<"Base"<<endl;
      }
        ~Base()
        {
              cout << "~Base" << endl;
                
        }
  private:
          int m_a;
            int m_b;

};

class A :public Base
{
  public:
      A()
      {
            cout << "A" << endl;
              
      }
        void fun()
        {
              cout << "fun" << endl;
                
        }
          ~A()
          {
                cout << "~A" << endl;
                  
          }
            void print()
            {
                  cout << "print" << endl;
                    
            }
  private:
              int a;
                int b;

};


int main()
{
    Base* p = new A();  //动态申请需要手动释放
      delete p;
      return 0;

}

我们看运行结果
在这里插入图片描述
我们可以看到,我们申请的是A的空间,但是却调用的是父类的析构函数,这就会导致我们的A空间里的部分没有被释放
因此在析构时,需要显式调用delete删除指针归还内存,否则就会造成内存泄漏。
怎么解决呢?
这就需要我们虚析构函数
我们需要在父类构造函数处加上virtual关键字

在这里插入图片描述

C++11提供了两个关键字检测是否重写

override //要求子类必须重写这个方法
final  //使程序不能被重写

强转后调用

我们来看代码:


    6 class Base
    7 {
    8       public:
    9             void virtual Func()
   10             {
   11                       cout<<"Base"<<endl;
   12 
   13             }
   14 
   15 };
   16 
   17 class Derived : public Base
   18 {
   19       public:
   20             void virtual Func()
   21             {
   22                       cout<<"Derived "<<endl;
   23 
   24             }
   25 
   26 };
   27 
   28 int main ()                                                                                                                                                        
   29 {
   30       Base* pBase = new Base();
   31           pBase ->Func();
   32               Derived * pDerived = (Derived*)pBase;
   33                   pDerived->Func();
W> 34                       delete pBase;
   35                         
   36                           pDerived  =  new Derived();
   37                               pBase = pDerived;
   38                                   pBase->Func();
   39                                     
W> 40                                       delete pDerived;
   41                                             return 0;
   42 

我们如果用父类指针指向一个子类,我们将这个父类指针强转成为子类指针类型,然后调用,调用的是父类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值