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的析构函数。最后一行打印的是派生类析构完,基类析构。

四、区别

隐藏(重定义) 重载 重写(覆盖)
范围 只在继承关系的两个类中 一个类中的两个函数 只在继承关系的两个类中
形成条件 同名 同名但能参数列表不同 虚函数,完全相同(例外:协变)
发布了77 篇原创文章 · 获赞 16 · 访问量 6524

猜你喜欢

转载自blog.csdn.net/weixin_43886592/article/details/102834185