成都网站建设设计

将想法与焦点和您一起共享

C语言到C++(基础语法二)-创新互联

一、函数重载         概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的 形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。

创新互联公司是一家专注网站建设、网络营销策划、成都小程序开发、电子商务建设、网络推广、移动互联开发、研究、服务为一体的技术型公司。公司成立十余年以来,已经为千余家成都发电机维修各业的企业公司提供互联网服务。现在,服务的千余家客户与我们一路同行,见证我们的成长;未来,我们一起分享成功的喜悦。
int add(int a, int b, int c)
{
    return a+b+c;
}


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


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

  思考下面一段代码,下面两个函数是否属于函数重载,他们有没有什么问题?

int func()
{
    return 0;
}

int func(int a=10)
{
    return a;
}


int main()
{
    func();
    func();
    return 0;
}

根据定义,函数名相同参数不同,他们当然构成重载函数,虽然他们构成重载函数,但是在使用时会有问题,因为调用函数时存在二异性。应该避免这种情况出现。

  函数重载原理

  先大概了解编译器编译程序过程(Linus下),现在有test. c、func.c、func.h三个文件。

1.预处理阶段,func.h头文件被展开、然后进行宏替换、条件编译、去注释。生成func.i和test.i两个文件。

2.编译阶段,检查语法,生成汇编代码。生成func.s和test.s文件。

3.汇编,汇编代码转化为二进制机器码,形成符号表。生成func.o和test.o文件。

4.链接,文件在链接阶段被分成几段进行操作。先进行合并段表,把相关文件对应的段连接到一起,然后对符号表进行合并和重定向。生成func.o和test.o链接生成a.out文件。

  C语言不支持函数重载,因为编译时两个重载函数函数名相同,在func.o符号表中存在歧义和冲突,其次链接时也有冲突,因为C语言中是直接使用函数名标识和查找。                

  而C++的目标文件符号表中不是直接使用函数名来标识和查找函数,它引入了函数名修改规则,通过参数的属性修改函数名。前面提到C++中函数重载的概念中必须有参数个数 或 类型 或 顺序的不同,通过这三种参数属性修改了函数名,不同编译器的修改规则不同。Linus下修饰规则为_Z+函数长度+函数名+参数类型首字母。       

 ​​​     通过这里我们就明白了为什么C语言不支持函数重载,因为同名函数无法区分,而C++使用函数修改规则通过参数的不同属性改变了函数名,从而就能支持重载。

二、引用         概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。类型&引用变量名(对象名)=引用实体。引用在语法层没有开辟新空间,相当于给原变量起一个新名称。下图我们会发现a和b的地址一样。

#includeusing namespace std;
int main()
{
	int a = 10;
	int& b = a;

    system("pause");
	return 0;
}
引用的特性

  1.引用在定义时必须初始化。

void test()
{
    //int& b;//编译会出错
}

  2.一个变量可以有多个引用。

void test()
{
    int a=10;
    int& b=a;
    int& c=a;
    int& d=b;
}

  3.引用一旦引用一个实体,再不能引用其他实体。

void test()
{
    int a=10;
    int& b=a;

    int c=15;
    b=c;//这里不是b引用c,而是把c的值赋给b,要和指针的使用区分
}
引用的使用

  1.引用做参数,功能与传指针参数类似。

//传指针
void swap(int* x,int* y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}

//传引用
void swap(int& x,int& y)
{
    int tmp=x;
    x=y;
    y=tmp;
}

int main()
{
    int a=10;
    int b=20;
    swap(&a,&b);
    swap(a,b);

    return 0;
}

2.引用做返回值 

在传值返回的函数中,因为函数执行完成后函数栈帧已经被销毁,会非法访问返回的变量,所以返回的值需要先存储在临时变量中。如果返回的对象较小不大于八个字节,一般是寄存器充当临时变量,如果比较大则存放在调用函数的栈帧内。所有的传值返回都会生成一个拷贝,当返回的数据量很大时使用引用做返回值效率会提高。

传值返回:

  

 

下面这段代码存在非法访问的问题,add函数的返回值是变量c的引用,当函数执行完成栈帧销毁后,访问了c的空间,如果add函数栈帧销毁时清理空间,那么取c值时取到的就是随机值。

#includeusing namespace std;

int& add(int x, int y)
{
	int c = x + y;
	return c;
}
int main()
{
    //非法访问c的空间
	int ret = add(10, 20);

	return 0;
}

  上面的例子是一个错误的用法,那么该如何使用引用返回?如果函数返回时,出了函数作用域,如果返回的对象还在(静态变量、全局变量等),则可以使用引用返回,否则必须使用传值返回。

#includeusing namespace std;

int& add(int x, int y)
{
	static int c = x + y;
	return c;
}
int main()
{
	int ret = add(10, 20);

	return 0;
}
  总结

  引用的作用主要体现在传参和传返回值

  1.引用传参和引用传返回值在有些场景下可以提高性能(大对象+深拷贝对象)

  2.引用传参和引用传返回值做输出型参数和输出型返回值。有些场景下形参的改变可以改变实参,引用返回可以改变返回对象。

  常引用
int main()
{
    const int a=10;
    int& b=a;//权限的放大,编译会出错,a只读而b可写

    const int& b=a;//权限不变,可编译通过

    int c=10;
    const int& d=c;//权限的缩小,编译可以通过
    return 0;
}

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网站标题:C语言到C++(基础语法二)-创新互联
链接分享:http://chengdu.cdxwcx.cn/article/dgspoo.html