C++继承(多态性)---隐藏 重写 重载

一、隐藏(重定义)

1、子类和父类中有同名成员或函数(非虚函数),子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义
2、如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
3、在继承体系中基类和派生类都有独立的作用域。

class Base //基类
{
public:
	int m_a;//重名成员变量
	Base() :
		m_a(10)
	{}
	void func() //重名成员函数
	{
		cout << "Base" << endl;
	}

};


class Test :public Base //派生类
{
public:
	int m_a;//重名成员变量
	Test() :
		m_a(20)
	{}
	void func()//重名成员函数
	{
		cout << "Test" << endl;
	}
};

在这里插入图片描述

此时,基类的成员将被隐藏,要想访问,两种方法:
1.定义一个基类的指针赋值给派生类,再通过基类的指针进行访问。
2.使用基类的作用域调用。
在这里插入图片描述

//方法1:
Test T ;
Base *Bptr = &T;
cout << T.m_a<< endl;
T.func();
cout << Bptr->m_a << endl;
Bptr->func();

//方法2:
Test T;
cout << T.m_a<< endl;
T.func();
cout << T.Base::m_a << endl;
T.Base::func();

在这里插入图片描述

建议:

1、不要把基类的地址赋值给派生类指针,极有可能产生越界
2、不要在派生类中定义跟基类成员同名的成员,也就不会右隐藏的问题了。

二、重载(函数)

只要函数名相同,参数列表不同就构成函数重载关系(只是返回值类型相同也不行)。

int add(int a, int b)
{
	return a + b;

}

int add(int a, int b,int c)
{
	return a + b + c;

}
int main()
{
    cout << add(1, 2) << endl;
    cout << add(1, 2, 3) << endl;
    return 0;
}

在这里插入图片描述

三、重写(覆盖)

1.定义:

1.基类里有一个虚函数和派生类里的一个虚函数完全一致(返回值,函数名,参数列表),则基类里的这个函数被派生类里的那个重名函数所重写(覆盖)
> 在这里插入图片描述
2.注意:重写只是在派生类中调用派生类里的那个虚函数,不会继承基类里的那个虚函数,而不会去改变基类里的那个重名的虚函数。
3.如果基类的函数为虚函数,此时派生类的函数只要定义,无论是否加virtual关键字,都与基类的函数构成重写。

class Base//基类
{
public:
	int m_a;
	virtual void func()//基类虚函数
	{
		cout << "Base" << endl;
	}
};

class Test : public Base//派生类
{
public:
	int m_b;
	virtual void func()//派生类虚函数
	{
		cout << "Test" << endl;
	}
};

int main()
{
	Base B;
	Test T;
	Base* Bptr = &T;
	T.func();
	Bptr->func();
	B.func();
    system("pause");
    return 0;
}

在这里插入图片描述

在这里插入图片描述
当基类里的虚函数和派生类的函数构成重载关系是

2.特例:协变

协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引 用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

class A{};
class B : public A {};
 
class Person 
{ 
public:   
 virtual A* f()
  {
    return new A;
  } 
};
 
class Student : public Person 
{ 
public: 
  virtual B* f()
   {
   return new B;
   }
 };

协变的深入了解

3.析构函数的重写

因为在C++中,类中的析构函数底层都是由destructor函数实现的,所以,经过编译后,基类和派生类析构函数都会处理成destructor,从而基类的析构函数会被派生类的析构函数重。

class Base
{
public:
	virtual~Base()
	{
		cout << "~Base" << endl;
	}
};

class Test : public Base
{
public:
	virtual~Test()
	{
		cout << "~Test" << endl;
	}
};

int main()
{
	
	Base* B1 = new Base;
	Base* B2 = new Test;//用一个基类对象指针指向一个派生类
	delete B1;//new一个基类对象,delete掉,没有涉及继承,所以只调用自己的析构函数。
	delete B2;
    system("pause");
    return 0;
}

在这里插入图片描述
**加粗样式**

在这里,B2是一个指向Test对象的Base*指针,目的是限制B2的作用域,B2只能作用于继承的基类那部分,基类的析构函数输出为 ~~Base,如果不被重写,则第二行应该打印的是~Base,由于析构函数底层实现的原理一致构成了重写,调用了Test的析构函数。最后一行打印的是派生类析构完,基类析构。

class A
{
public:
	A()
	{
		cout << "A\n";
	}
	virtual ~A()
	{
		cout << "~A\n";
	}
};

class B : public A
{
public:
	B()
	{
		cout << "B\n";
	}
	virtual ~B()
	{
		cout << "~B\n";
	}
};

总结:

A* a = new a; B* b = new b; delete a; detele b;A* a = new a; B* b = new b; delete a; detele b;(两个析构为虚析构函数)A* a = new B; delete a;A* a = new B; delete a;(两个析构为虚析构函数)A* a = new A;B* b = dynamic_cast<B*>(a);delete a;delete b;
A A B ~A ~B ~AA A B ~A ~B ~AA B ~AA B ~B ~AA ~A

四、区别

隐藏(重定义)重载重写(覆盖)
范围只在继承关系的两个类中一个类中的两个函数只在继承关系的两个类中
形成条件同名同名但能参数列表不同虚函数,完全相同(例外:协变)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值