C++中同名函数之间的关系

在C++中同名函数有三种关系:

  • 重载(overlode):相同作用域;函数名相同;参数列表不同(参数类型不同,或者参数个数不同,或者参数个数和参数类型都不相同);返回类型随意。
  • 覆盖(override):不同作用域下(分别在父类和子类中);函数名相同;参数列表列表相同;返回类型相同(协变除外);基类函数必须有virtual修饰;父类和子类的访问限定可以不同。
  • 隐藏(overhide):不同作用域下(分别在父类和子类中);函数名相同;除过覆盖的同名函数都是隐藏关系。

一:重载

产生原因:主要是因为在C++中,编译器在编译.cpp文件中当前作用域的同名函数时,函数生成的符号由返回值类型(不起决定作用)+形参类型和顺序(起决定作用)的组成。

作用:用同一个函数名命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

int sum(int a,int b)
{
	return a+b;
}

double sum(double a,double b)
{
	return a+b;
}
float sum(float a,float b)
{
	return a+b;
}

int main()
{

	/*
	调用函数名相同的函数,
	根据实参的类型和实参的顺序以及实参的个数选择相应的函数
	*/
	int a=sum(10,20);//调用的是int sum(int a,int b)
	//call   sum (010B1447h) ==》  静态的绑定
	float b=sum(2.5f,3.2f);//调用的是float sum(float a,float b);
	//call   sum (010B145Bh) ==》  动态的绑定
	
	cout<<a<<endl;
	cout<<b<<endl;
	return 0;
}

同样的如下也构成重载

void add(int* a)//参数类型不同
{
	cout<<*a<<endl;
}
void add(int& a)
{
	cout<<a<<endl;
}
int main()
{
	int a=10;
	add(&a);
	add(a);
}

二、覆盖

在子类中定义了一个与父类完全相同的函数时,称子类这个函数覆盖了父类的这个虚函数。完全相同代表着两个函数的函数名、参数个数、参数类型、返回值类型都相同;也有特殊例子(协变)。

覆盖的作用:实现动态的多态。

第一种情况:

//情况一:普通情况
class Base
{
public:
	virtual void Show()
	{
		cout<<"Base::Show()"<<endl;
	}
protected:
	int ma;
};

class Derive:public Base
{
public:
	/*在子类中定义了一个和父类虚函数完全相同的函数;
	  如果不显示加上virtulal修饰,编译器会默认为虚函数。
	*/
	void Show()
	{
		cout<<"Derive::Show()"<<endl;
	}
protected:
	int mb;
};

void Fun(Base* p)
{
	p->Show();
}
void Fun(Base& p)
{
	p.Show();
}

int main()
{
	Base p;
	Derive d;
	Fun(p); 
	Fun(&p);
	
	/*
	打印的是Derive::Show()
	父类的引用引用了基类的对象,调用覆盖函数时调用的是基类的虚函数
	*/
	Fun(d);
	
	/*
	打印的是Derive::Show()
	父类的指针指向了基类的对象,调用覆盖函数时调用的是基类的虚函数
	*/
	Fun(&d);//打印的是Derive::Show()
	return 0;
}

第二种情况:

协变:子类的虚函数和父类中的虚函数的函数名、参数个数、参数类型都相同,只是返回值类型不同,父类的虚函数返回的时父类的指针或者引用,子类的虚函数返回的时子类的指针或者引用,这种情况下也会产生子类的虚函数覆盖父类的虚函数。

//情况二:协变覆盖
class Base
{
public:
	virtual Base& Show()//基类的虚函数返回基类的引用
	{
		cout<<"Base::Show()"<<endl;
		return *this;
	}
protected:
	int ma;
};

class Derive:public Base
{
public:
	Base& Show()//子类的虚函数,返回子类的引用
	{
		cout<<"Derive::Show()"<<endl;
		return * this;
	}
protected:
	int mb;
};

void Fun(Base* p)
{
	p->Show();
}

void Fun(Base& p)
{
	p.Show();
}

int main()
{
	Base p;
	Derive d;
	Fun(p);
	Fun(&p);

	Fun(d);//call   eax
	Fun(&d);
	return 0;
}

三、隐藏:

隐藏的不光是成员函数,还可以是成员变量。

★在子类的内部或者外部(通过子类成员)访问该成员,全部访问的子类同名成员。

★在子类的内部或者外部(通过子类成员)访问该同名的成员函数,调用的是子类的成员函数。

class A
{
public:
	A(int x=10):ma(x),mb(x){}

	//举例1
	//void Show()
	//{
	//	cout<<"A::Show()"<<endl;
	//}

	//举例2
	//virtual void Show()
	//{
	//	cout<<"A::Show()"<<endl;
	//}

	//举例2
	void Show(int a)
	{
		cout<<"A::Show(int)"<<endl;
	}
public:
	int ma;
	int mb;
};
class B:public A
{
public:
	B(int x=20):ma(x){}
	//举例1
	//void Show()
	//{
	//	cout<<"B::Show()"<<endl;
	//	cout<<ma<<endl;//在子类中访问同名的成员,访问的是子类中的
	//}

	//举例2
	//void Show(int a)
	//{
	//	cout<<"B::Show()"<<endl;
	//	cout<<ma<<endl;
	//}

	//举例3
	void Show(int a,int b)
	{
		cout<<"B::Show()"<<endl;
		cout<<ma<<endl;
	}
public:
	int ma;
};
/*
A::
	B::
		ma
		mb
	ma
*/
int main()
{
	B b;
	cout<<(b.ma)<<endl;
	cout<<(b.mb)<<endl;
	//b.show(1);
	b.Show(1,2);
	return 0;
}

 

  • 13
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
c 自动生成函数调用关系图是一种功能强大的工具,用于分析和可视化一个C程序函数之间的调用关系。利用这个工具,我们可以更好地了解函数之间的依赖关系,帮助我们在程序开发和维护过程更高效地进行代码阅读和调试。 生成函数调用关系图的过程如下: 1. 首先,通过静态分析和解析C程序的源代码,解析器可以识别出所有的函数声明和函数定义,并建立函数之间关系。 2. 然后,解析器可以根据函数之间的调用关系,构建一个函数调用图。该图以函数作为节点,调用关系作为边进行表示。每个节点包含函数的名称和所在的文件位置信息。 3. 接下来,解析器可以使用图的遍历算法,例如深度优先搜索或广度优先搜索,遍历函数调用图,将遍历的路径记录下来。这样,我们就可以得到从一个函数到另一个函数的调用路径。 4. 最后,解析器将调用路径和函数调用图结合起来,生成一个函数调用关系图。该图可以是一个可视化的图形界面,也可以是一个文本文件,记录了函数之间的调用关系。 通过函数调用关系图,我们可以很方便地找到一个函数被哪些函数调用,以及哪些函数被该函数调用,进而帮助我们分析函数之间的依赖关系和调用流程。这对于程序的理解、代码重构和错误调试都非常有帮助。 总的来说,c 自动生成函数调用关系图是一个功能强大的工具,可以帮助我们更好地了解和分析C程序函数之间的调用关系,提高代码的可读性和维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值