C++ -- 类成员函数的重载、重写和隐藏

本文详细解释了类成员函数的重载、覆盖和隐藏的区别,包括重载函数的特征、覆盖函数的特性以及隐藏机制的原理。通过具体的例子,展示了在不同场景下这些概念的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类成员函数的重载、覆盖和隐藏的区别

1、成员函数的重载

函数名相同,但是参数的个数或参数的类型不同,编译后重载的函数都具有不同的地址,重载可以针对运算符,而覆盖不行.

成员函数被重载的特征:

    a. 相同的范围,作用域(同一个类中)

    b. 函数名相同,参数不同

    c. virtual关键字可有可无

class Animal
{
public:
	void eat(char a);
	void eat(char a,int b);
	void eat(int a,char b);
};

同一个类Animal中,有3个同名的成员函数,但是参数类型互不相同,它们互为重载函数。

注意:重载函数和返回值的类型无关。

2、覆盖

也叫重写,只对类的构造函数或成员函数适用,是子类继承父类时才使用的非常有用的功能,真正和多态相关,它们的地址在编译时无法确定,在运行时动态分配。

派生类函数覆盖基类函数,特征是:

    a. 不同的范围(分别位于派生类与基类) 

    b. 函数名相同,参数相同(类型相同,顺序相同),返回值类型相同

        所有都必须和基类中被重写的函数一致,只有函数体不同。

    c. 基类函数必须有virtual关键字                                                  

class Animal
{
public:
	virtual void eat(char a)
	{
		cout<<"Animal::eat() "<<a<<endl;
	}
};
//Cat公有继承Animal,否则基类的指针不能指向派生类
class Cat:public Animal
{
public:
	//重写了基类的eat()函数,函数名参数都相同,基类有Virtual,子类和派生类之间。
	void eat(char b)
	{
		cout<<"Cat::eat() "<<b<<endl;
	}
};
int main()
{
	Animal dongwu;
	Cat mao;
	Animal *p = &dongwu;	
	p->eat('g');
	dongwu.eat('g');
	p = &mao;
	p->eat('r');
	mao.eat('r');	
	system("pause");
	return 0;
}

输出显示:

3、隐藏

指派生类的函数屏蔽了与其同名的基类函数

    a. 如果派生类的函数与基类的函数同名,但是参数不同,此时,无论有无virtual关键字,基类的函数将被隐藏

    b. 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字, 此时,基类的函数被隐藏。

    1)子类和父类之间的同名函数,参数不同

class Animal
{
public:
	void eat(char a)
	{
		cout<<"Animal::eat() "<<a<<endl;
	}
};

class Cat:public Animal
{
public:
	//隐藏,函数名相同,参数不同,有无virtual无所谓
	void eat(char c,int i)
	{
		cout<<"Cat::eat() "<<c<<" and "<<i<<endl;
	}
};
int main()
{
	Cat mao;	
	mao.eat('r',5);	
	//mao.eat('g');//出错,因为基类的函数被隐藏
	system("pause");
	return 0;
}

     2)参数相同,无virtual关键字  

class Animal
{
public:
	void eat(char a)
	{
		cout<<"Animal::eat() "<<a<<endl;
	}
};

class Cat:public Animal
{
public:
	//隐藏,函数名相同,参数不同,无virtual,和返回值的类型无关
	bool eat(char c)
	{
		cout<<"Cat::eat() "<<c<<endl;
		return true;
	}
};
int main()
{
	Cat mao;	
	mao.eat('r');//调用Cat类的eat函数
	system("pause");
	return 0;
}

举例:

1)重写和隐藏

#include <iostream>
using namespace std;

class Base
{
public:
	virtual void eat()
	{
		cout<<"Base"<<endl;
	}
};
class Child1:public Base
{
public:
	void eat()
	{
		cout<<"Child1"<<endl;
	}
};
class Child2:public Base
{
public:
	void eat(int n) 
	{
		cout<<"Child2"<<endl;
	}
};
int main()
{
	Base ba;
	Child1 c1;
	Child2 c2;
	/*
	   重写的特点
	   1)子类和父类之间的同名虚函数,基类必须有virtual。
	   2) 函数的名字相同,参数相同,返回值相同,所有都相同,除了(所在的范围和函数体)
	*/
	Base *p;//定义一个基类的指针

	//**  指针p指向Base的对象
	p = &ba;
	p->eat();//调用Base的eat()函数

	//**  指针p指向Child1的对象
	p = &c1;
	p->eat();//Child1继承了Base并重写了eat()虚函数,所以会动态调用重写后的eat()

	//**  指针p指向Child2的对象
	p = &c2;
	p->eat();//Child2也继承了Base,并重新定义了一个eat(int)带一个参数的函数,这不叫重写,是隐藏,所以还会调用Base的eat();
	//c2.eat();
	c2.eat(2);//会调用隐藏的那个函数。
	system("pause");
	return 0;
}

输出结果:

2)重载和重写

#include<stdio.h>
class A
{
   public:
	   void FuncA()
	   {
		   printf("FuncA called\n");
	   }
	   virtual void FuncB()
	   {
		   printf("FuncB called\n");
	   }
};

class B:public A
{
  public:
	  void FuncA()
	  {
		  A::FuncA();
		  printf("FuncAB called\n");
	  }
	  virtual void FuncB()
	  {
		  printf("FuncBB called\n");
	  }
};

void main()
{
	B b;
	A *pa;
	pa=&b;
	A *pa2=new A;
	b.FuncA();
	printf("*\n");
	b.FuncB();
	printf("*\n");
	pa->FuncA();
	printf("*\n");
	pa->FuncB();
	printf("*\n");
	pa2->FuncA();
	printf("*\n");
	pa2->FuncB();
	delete pa2;
}

输出结果:


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值