c++构造函数的重载,c语言函数重载是什么
写在前面
先说我的状态。五一是一个为期五天的假期。这几天都在玩,很少学习。我不后悔,也没必要。本来放假就是为了放松自己。我唯一要反思的是,别人在学,我自己心里想学,却学不会。这是我的缺点。我以后会克服的。试着尽快和你分享我的知识。今天,我和你们分享C和函数重载的关系。我们需要学习如何使用重载。
函数重载我们可能对函数很熟悉,但是重载是什么意思呢?下面用一个具体的场景来分享一下。
有一天,张三老板让你写一个两位数相加的函数。张三想,这不简单吗?动动手指,结果就出来了。很简单。
int add(int x,int y)
{
返回x y;
}
现在老板一看张三的代码就怒不可遏。你怎么想呢?我想把12和10.9相加怎么办?这个只能加两个整数,回去修改!张三听到老板的话,忍不住反驳道:“这个我怎么改?我又不会写add1,add 2……”老板听到张三的嘟囔,生气地说:“你没学过函数重载吗?”看看下面的代码,回去好好学习,基础不扎实。
张看到代码的时候很惊讶。C还能这么写吗?太好了,我想读一本好书。
int add(int x,int y)
{
返回x y;
}
double add(double x,int y)
{
返回x y;
}
double add(int x,double y)
{
返回x y;
}
我们不希望这种事情发生在张三身上。我们先来看看函数重载的定义。
函数重载:它是函数的特例。c允许在同一个作用域中声明几个具有相似函数的同名函数。这
参数列表(参数的个数、类型或顺序)必须不同,常用于处理函数相似的不同数据类型的问题。
可能你不喜欢这个定义,我给你总结一下。
函数重载应满足以下要求。
函数名相同参数的类型、个数、顺序不同。返回类型不需要函数重载的原则。一般我们知道可以应用函数重载,但是对于我们来说,需要看看它们的原理。为什么C语言不支持重载,而C支持?这些都是问题。
为什么C可以支持重载?我们先用C编译器简单看一下如何执行程序。下面是我在Linux环境下用G做的事情。如果不是很了解,可以忽略,直接了解c的原理.
我们先看现象,发现C能准确找到需要匹配的函数,这也是我们不解的地方。
//test.h
#杂注一次
#包括iostream
#包含stdio.h
使用STD:cout;
void func(int a,double b);
void func(double a,int b);
//test.cpp
#包含“test.h”
//写两个函数形成重载。
void func(int a,double b)
{
printf(%d %lf ,a,b);
}
void func(double a,int b)
{
printf(%lf %d ,a,b);
}
//Mian.cpp
#包含“test.h”
int main()
{
func(10,2.20);
返回0;
}
关于这一点,我们先简单说一下,之前已经详细讲过了。文件成为可执行程序需要以下四个步骤。
宏替换头文件,展开注释,替换main.cpp-main.i test.cpp-test.i编译检查语法,代码转换成汇编语言main.i-main.s test.i-test.s汇编语言变成二进制语言,每个文件变成目标文件main.s-main.o test.s-test.o链接多个目标文件链接库。
这里我们需要关注链接,这是我们一天中最重要的部分。
链接只是目标文件的组合吗?不,它有很多任务要完成,其中最重要的是找到函数的地址,链接起来,合并在一起。
当我们展开头文件时,Main.cpp中有func函数的声明和调用,在编译和汇编的过程中,有一个符号表,记录着函数的定义和对应的映射。这一点非常重要。符号表包含函数的名称和地址。
每个目标文件(。o)包含一个符号表和一系列指令。我们来看看输入和完成函数的链接。
现在是mian.o的指令,之前的一些指令都正常工作,直到遇到func这个点。如果你看过C语言的汇编语言,可能对下面这些比较熟悉。
在func,编译器开始调用(func:),编译器不知道func的地址,但是func函数已经在头文件的扩展中声明了,所以编译器知道func是一个函数,所以先给它一个无效地址。当程序被链接时,编译器会看到这是一个无效的地址,并且会用other中的符号表来触碰函数名。o文件,遇到就填,找不到就报连接错误。
可以理解为什么C在这里不支持重载。当我们接触函数名时,符号表中有很多相同的函数名,所以编译器不会识别使用哪一个。更何况,函数名相同的c文件有时无法编译。
Gcc对函数名不做任何处理,这也是C语言不支持函数重载的原因。
为什么C在这里可以支持函数重载?我们可以得到结果。由于无效函数在链接时会触及其他符号表中的函数名,所以我们只需要看看重载的函数名是否相同。你可能会困惑。重载的函数名不是一样的吗?是的,但是C编译器会做一些事情。这里的每个编译器都有自己的修改函数名的规则。这就是C支持重载的原理。
这就是为什么C可以支持重载,G的函数修改后改成[_Z函数名长度函数名类型首字母1类型首字母2……]的原因,这也是为什么我们只要求参数列表,不要求返回值。
用C语言互相调用。我们都知道C支持C语言的大部分语法。C和C语言可以互相调用吗?其实是有可能的。在一个大型程序中,有些部门可能用C写的函数,有些部门可能用C,如果不能互相使用,就要面对面。
要创建一个静态库,我们可以把自己的代码编译成静态库或者动态库。这里我以一个静态库为例,看看如何在VS .
调用C我们已经有了一个C语言的静态库,现在一个C项目需要使用这个静态库。我们如何使用它?它需要以下步骤。
下面两张图都是修改环境的设置。我用的是VS2013,其他的应该差不多。请依次修改它们。
这里我们可以调用C语言的静态库。让我们看看结果。
#包含././heap/heap/heap . h //相对路径
int main()
{
MyHeap myHeap
InitMyHeap(我的堆);
HeapPush( myHeap,1);
HeapPush( myHeap,2);
HeapPush( myHeap,3);
显示(my heap);
返回0;
}
为什么这是错的?我们不是已经建立了静态库吗?其实这种错误很容易分析。当C调用C语言中的函数时,C会自动修改函数名。当时C语言没有,所以不会遇到,链接会出错。
extern“C”既然编译器不能自动识别C语言的函数名,难道就不能直接告诉编译器吗?Extern "c "就是这样一个函数。
C工程中有时可能需要用C的风格编译一些函数,在函数前面加上extern“C”,意思是告诉编译器,
按照C语言的规则编译函数。比如tcmalloc是google用C实现的项目,提供了tcmallc()和tcfree。
两个接口来用,但是如果是C项目就不能用了,所以他用extern“C”来解决。
Extern C //告知这是C语言中的函数声明
{
#包含././Heap/Heap/heap.h
}
int main()
{
MyHeap myHeap
InitMyHeap(我的堆);
HeapPush( myHeap,1);
HeapPush( myHeap,2);
HeapPush( myHeap,3);
显示(my heap);
返回0;
}
extern“C”的原理我们需要看看extern“C”的原理。使用extern“C”后,在编译C时,按照C语言的方法修改函数名,而不是变成C的规则,extern‘C’可以单独修改函数,也可以修改一系列函数,使用代码块。
//test.h
#杂注一次
#包括iostream
#包含stdio.h
extern C void func(int a,double b);
//test.cpp
#包含“test.h”
//写两个函数形成重载。
void func(int a,double b)
{
printf(%d %lf ,a,b);
}
//Mian.cpp
#包含“test.h”
int main()
{
func(10,2.20);
返回0;
}
C调用C,那么C能调用C吗?可以,但是也需要一些段落来完成。C语言如何识别C的规则?这是我们需要考虑的。
我们把这个库变成了c语言的静态库。
#包含././Heap/Heap/heap.h
int main()
{
MyHeap myHeap
InitMyHeap(我的堆);
HeapPush( myHeap,1);
HeapPush( myHeap,2);
HeapPush( myHeap,3);
显示(my heap);
返回0;
}
不能让C语言的编译器识别C的函数名,那么能不能一编译完函数就把函数名写完?按照C语言来说,很简单。
但即便如此,C语言还是会报错,因为头文件展开时,C语言根本不识别extern“C”,所以我们需要条件编译。
条件编译修改静态库的方法如下,需要重新编译。
//方法1
#ifdef __cplusplus //C唯一
# define EXTERNC extern C
#否则
#定义外部c
#endif
EXTERNC extern void InitMyHeap(my heap * pHeap);
EXTERNC extern void heap push(my heap * pHeap,HP datatype x);
EXTERNC extern bool is full(my heap * pHeap);
EXTERNC extern bool IsEmpty(my heap * pHeap);
EXTERNC extern int heap size(my heap * pHeap);
EXTERNC extern void adjust down(my heap * pHeap);
EXTERNC extern void adjustUp(my heap * pHeap);
EXTERNC extern void显示(my heap * pHeap);
EXTERNC extern HP datatype HeapTop(my heap * pHeap);
EXTERNC extern void heap pop(my heap * pHeap);
//方法2
#ifdef __cplusplus
外部 C
{
#endif
extern void InitMyHeap(my heap * pHeap);
extern void heap push(my heap * pHeap,HP datatype x);
extern bool is full(my heap * pHeap);
extern bool IsEmpty(my heap * pHeap);
extern int heap size(my heap * pHeap);
extern void adjust down(my heap * pHeap);
extern void adjustUp(my heap * pHeap);
extern void显示(my heap * pHeap);
extern HP datatype HeapTop(my heap * pHeap);
extern void heap pop(my heap * pHeap);
#ifdef __cplusplus
}
#endif,就是这样。
注意,这里有一点需要注意。当我们的C语言调用C静态库时,至少我们实际需要的那部分代码不能在extern‘C’修饰的函数中重载。
C注本注以extern C 为主,部分远程内容需要注意。
# #由extern c 修饰的函数与函数完全相同
extern C 修饰的函数模块外有一个相同的函数,此编译器不会传递它。
#ifdef __cplusplus
外部 C
{
#endif
void func(int a,int b)
{
printf(C : %d %d\n ,a,b);
}
#ifdef __cplusplus
}
#endif
//完全一样。
void func(int a,int b)
{
printf(C : %d %d\n ,a,b);
}
由extern“C”修改的函数和一个函数构成了重载。函数在由extern“C”修改的函数模块外部构成重载。这个编译器可以通过,但是extern C 修改的命名方法还是C语言的方式,重载是C .
#包括iostream
使用命名空间std
#ifdef __cplusplus
外部 C
{
#endif
void func(int a,int b)
{
printf(C : %d %d\n ,a,b);
}
#ifdef __cplusplus
}
#endif
void func(double a,int b)
{
printf(C : %lf %d\n ,a,b);
}
int main()
{
func(1,2);
func(1.11,2);
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。