C++重载详解

重载就是同名而非同义,具体意义根据上下文的语境而言。

重载规则:

1,函数名相同。

2,参数个数不同,参数的类型不同,参数顺序不同,均可构成重载。

3,返回值类型不同则不可以构成重载。

函数重载(静多态)

void print(int a)
{
//...
}
void print(int a,char b)
{
//...
}
void print(char a,int a)
{
//...
}
//根据参数的数序,个数执行上下文。

匹配原则:

1,严格匹配,找到则调用。

2,通过隐式转换寻求一个匹配,找到则调用。

void print(int a)
{
printf("void print(int a)\n");
}
void print(char a)
{
printf("void print(char a)\n");
}
void print(float a)
{
printf("void print(float a)\n");
}
void print(double a)
{
printf("void print(double a)\n");
}
int main()
{
printf(3.4);//3.4是double类型,如果上述没有double类型,他会转向int,float类型,但是两者同时又的话,会报错产生二义性,不要让计算机去解决一些事情。
print('a');//如果没有char类型最终会转向int类型。字符是以asscII码存在,也就是int类型。
}

int 到 long 和 double,double 到 int 和 float 隐式类型转换。遇到这种情型,则会引起二义性。

如果使用时遇到二义性的,在使用时经过强转即可。

void print(int a)
{
printf("void print(int a)\n");
}
void print(char a)
{
printf("void print(char a)\n");
}
void print(float a)
{
printf("void print(float a)\n");
}
/*void print(double a)
{
printf("void print(double a)\n");
}*/
int main()
{
print(3.14);// error: call of overloaded 'print(double)' is ambiguous
print((int)3.14);
print((float)3.14);
/*
void print(int a)
void print(float a)
*/
}

重载的原理

name mangling(倾轧)

void print(int a)//print_i
{
printf("void print(int a)\n");
}
void print(char a)//print_ic
{
printf("void print(char a)\n");
}
void print(float a)//...
{
printf("void print(float a)\n");
}
void print(double a)//...
{
printf("void print(double a)\n");
}
int main()
{
print(3.14);//重载函数之间底层处理技术倾轧,把相同的函数名倾轧成不同的函数名。
return 0;
}

声明.h文件

#ifndef PRING_H
#define PRING_H
extern "c"//不倾轧
{
void print(int a)
void print(char a)
void print(int a,char b)
void print(char a,int b)
} #endif //PRING_H
#include<iostream>
#include "print.h"
using namespace std;
int main()
{
int a,char b;
print(a);
return 0;
}

函数的定义部分.cpp文件

void print(int a)//print_i
{
printf("void print(int a)\n");
}
void print(char a)//print_ic
{
printf("void print(char a)\n");
}
void print(float a)//...
{
printf("void print(float a)\n");
}
void print(double a)//...
{
printf("void print(double a)\n");
}

要求是每个倾轧时要同时,不同的话则报错。c++要完全兼容C,标准C库是没有倾轧的。但是写头文件时要包含的c++中,c++便宜的时候就会有倾轧的文件,这时候就会链接不上。所以为了连接上在自己写的头文件上要求不要倾轧。extern "c"或者extern "c" {多行的情况}

操作符重载

C++认为一切操作符都是函数,函数是可以重载的。=>操作符是可以重载的。(并不是所有的运算符都可以重载)

struct Complex{
float a;
float b;
}
int main(){
Complex aa = {1,2},bb = {2,3};
Complex cc = aa + bb;//error return 0;
}

对操作符进行重载

struct Complex
{
float a;
float b;
}
Complex operator+(Complex a,Complex b)
{
Complex c;
c.a = a.a + b.a;
c.b = a.b + b.b;
return c;
}
int main()
{
Complex aa = {1,2},bb = {2,3};
Complex cc = aa + bb;//right
cout<<"cc = "<<"("<<cc.a<<","<<cc.b<<")"<<endl;
return 0;
}
//cc = (3,5),实现了结构体之间的加法,当然也可以用函数实现一个加法的过程

默认参数(default parameters)

#include<iostream>
#include<time.h>
using namespace std;
void weatherCast(string w = "pm=2.5")//默认参数
{
time_t t = time(0);//1970,0:0:0的毫秒数
char tmp[64];
strftime(tmp,sizeof(tmp),"%Y/%m/%d %x %A",localtime(&t));
cout<<tmp<<"today is weather "<<w<<endl;
}
int main()
{
weatherCast();
weatherCast("sunshine");
return 0;
}
//2018/03/04 03/04/18 Sundaytoday is weather pm=2.5
//2018/03/04 03/04/18 Sundaytoday is weather sunshine

多参数之间的默认参数,从右至左默认,中间不能跳跃。

实参的个数+默认的参数个数 >= 形参的个数

int volume(int l = 3,int w = 4,int h = 5)
{
return l*w*h;
}
int main()
{
cout<<volume()<<endl;
cout<<volume(2,2)<<endl;
cout<<volume(2,2,2)<<endl;
return 0;
}
/*
60
20
8
*/

默认参数与重载的冲突

void print(int a)
{
printf("void print(int a)");
}
void print(int a,int b = 100)
{
printf("void print(int a,int b = 100)");
}
int main()
{
print(1,200);
//void print(int a,int b = 200
print(1);//报错
return 0;
}

一个参数或者是两个参数的形式,重载,默认参数都是可以实现的,但是不可以两者同时存在。(在函数重载实现默认参数时要注意,二义性)

引用

变量名,本身是一段内存的引用,即别名(alias)。此处引入的引用,是为己有变量起一个别名。

int main()
{
int a = 500;//变量名的实质是一段内存空间的别名
int&ra = a;//ra是a的引用
printf("sizeof(ra) = %d sizeof(a) = %d\n",sizeof(ra),sizeof(a));
printf("&a = %p &ra = %p\n",&a,&ra);
a = 1000;
printf("a = %d ra = %d\n",a,ra);
ra = 1000;
printf("a = %d ra = %d\n",a,ra); int b = 200;
// int&ra = b;//报错
ra = b;//这是赋值 int&rb = ra;
printf("a = %d ra = %d ra = %d\n",a,ra,rb);
int&rbc = rb;
printf("a = %d ra = %d ra = %d rbc = %d\n",a,ra,rb,rbc);
return 0;
}
/*
sizeof(ra) = 4 sizeof(a) = 4
&a = 0061fea8 &ra = 0061fea8
a = 1000 ra = 1000
a = 1000 ra = 1000
*/ /*
a = 1000 ra = 1000 ra = 1000
a = 1000 ra = 1000 ra = 1000 rbc = 1000
*/

1 引用是一种声明关系,声明的时候必须要初始化,引用不开辟空间

2 此种申明关系,一经声明,不可变更

3 可以对引用再次引用,多次引用的结果是多个引用指向同一个变量

规则

1,引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地址。

2,声明的时候必须初始化,一经声明,不可变更。

3,可对引用,再次引用。多次引用的结果,是某一变量具有多个别名。

4,&符号前有数据类型时,是引用。其它皆为取地址。

应用场景:

void swap(int *pa,int *pb)
{
*pa ^= *pb;
*pb ^= *pa;
*pa ^= *pb;
}
void swap1(int &pa,int &pb)//利用引用传参,从c++的角度看没有开辟空间
{
&pa ^= &pb;
&pb ^= &pa;
&pa ^= &pb;
}
int main()
{
int a = 3;int b = 5;
int c = 3;int d = 5;
swap(a,b);
cout<<"a = "<<a<<" b = "<<b<<endl;
swap1(c,d);
cout<<"c = "<<c<<" d = "<<d<<endl;
return 0;
}
/*
a = 5 b = 3
c = 5 d = 3
*/

指针的引用

void swap(char **pa,char **pb)
{
char *t = pa;
*pa = *pb;
*pb = t;
}
int main()
{
char *pa = "chaina";
char *pb = "america";
cout<<"pa = "<<pa<<"pb = "<<pb<<endl;
swap(pa,pb);//上述swap()函数中使用二级指针才可以实现交换。
cout<<"pa = "<<pa<<"pb = "<<pb<<endl;
return 0;
}
/*
pa = chainapb = america
pa = americapb = chaina
*/

指针的引用可以实现平级内的交换,不开辟空间

void swap(char* &pa,char* &pb)
{
char *t = pa;
pa = pb;
pb = t;
}
int main()
{
char *pa = "chaina";
char *pb = "america";
cout<<"pa = "<<pa<<"pb = "<<pb<<endl;
swap(pa,pb);//上述swap()函数中使用二级指针才可以实现交换。
cout<<"pa = "<<pa<<"pb = "<<pb<<endl;
return 0;
}
/*
pa = chainapb = america
pa = americapb = chaina
*/

引用的本质是对指针的再次包装,指针是有引用的,不应该有引用的地址

引用的提高

引用的本质是指针,C++对裸露的内存地址(指针)作了一次包装。又取得的指针的优良特性。所以再对引用取地址,建立引用的指针没有意义。

1 可以定义指针的引用,但不能定义引用的引用

int *p;
int * & rp = p;//指针的引用 int a;
int & ra = a;
int & & raa = ra;//错误,没有引用的引用

2 可以定义指针的指针(二级指针),但不能定义引用的指针。

int **p;//二级指针
int a;
int &ra = a;
int & * p = &ra;//引用本身就是对指针的包装,再把引用打开包。与设计理念相悖。
//int * & ==>合法 指针的引用
//int & * ==>不合法 引用的指针

3,可以定义指针数组,但不能定义引用数组,可以定义数组引用。

int x,y,x;
int *p[] = {&x,&y,&z};//指针数组 int & rp[] = {x,y,x};//报错,引用数组,rp首元素,相当于int & * int arr[] = {1,2,3,4,5};//int * 类型 对他引用就变成int * &,指针的引用
int * &rarr = arr;//报错,缺大小。
int (&rarr)[5] = arr;//right
int [5] &rarr = arr;//报错
int &rarr [5] = arr;//error,引用的数组

常引用

const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一些特性。

(1)const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不合法的。这个原因比较简单。既然对象是 const 的,表示不能被修改,引用当然也不能修改,必须使用 const 引用。实际上,const int a=1; int &b=a;这种写法是不合法的,编译不过。

(2)const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。这个是const 引用与普通引用最大的区别。const int &a=2;是合法的。double x=3.14; const int&b=a;也是合法的。

const不可以改,也不可通过指针或者引用去改变。

常引用原理:

const 引用的目的是,禁止通过修改引用值来改变被引用的对象。const 引用的初始化特性较为微妙

const int a = 100;//对a取地址是 const int *
int *p = &a;//c中可以,c++中不可
const int *p = &a;//C++ const int &ra = a;//必须添加const int a;
double & ra = a;//报错,类型必须一致
const double & ra = a;//right int y;
const int & ry = y;
int a = 200;
int & ra = a;
const double & rb = a;//他在底层用一个临时变量交换,double tmp = a;const double &rd = tmp;const修饰无法改变。
cout<<"a = "<<a<<endl;
cout<<"ra = "<<ra<<endl;
cout<<"rb = "<<rb<<endl;
a = 400;
cout<<"a = "<<a<<endl;
cout<<"ra = "<<ra<<endl;
cout<<"rb = "<<rb<<endl; cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
cout<<"&rb = "<<&rb<<endl; /*
a = 200
ra = 200
rb = 200 a = 400
ra = 400
rb = 200 &a = 0x61fe8c
&ra = 0x61fe8c
&rb = 0x61fe90
*/

尽可能使用 const

use const whatever possible 原因如下:

1,使用 const 可以避免无意修改数据的编程错误。

2,使用 const 可以处理 const 和非 const 实参。否则将只能接受非 const 数据。

3,使用 const 引用,可使函数能够正确的生成并使用临时变量(如果实参与引用参数不匹配,就会生成临时变量)

引用和指针实质是一样的

C/C++(C++重载,默认参数,引用)的更多相关文章

  1. Python:默认参数

    Python是个人最喜欢的语言,刚开始接触Python时,总觉得有很多槽点,不太喜欢.后来,不知不觉中,就用的多了.习惯了.喜欢上了.Python的功能真的很强大,自己当初学习这门语言的时候,也记录过 ...

  2. python定义函数时默认参数注意事项

    如果在调用一个函数时,没有传递默认参数,则函数内的默认参数是对函数的默认参数属性__defaults__的引用, 如 def func(arg1=[]): arg1.append(2) 调用func时 ...

  3. 在python函数中默认参数的一些坑

    一.默认参数 python为了简化函数的调用,提供了默认参数机制: 这样在调用pow函数时,就可以省略最后一个参数不写: 在定义有默认参数的函数时,需要注意以下: 必选参数必须在前面,默认参数在后: ...

  4. 【C/C++】函数的默认参数/函数的占位参数/函数重载/注意事项

    函数的默认参数 返回值类型 函数名(参数=默认值){} #include <iostream> using namespace std; int func(int a = 10, int ...

  5. C++函数重载遇到了函数默认参数情况

    一.C++中的函数重载 什么是函数重载? 我的理解是: (1)用一个函数名定义不同的函数: (2)函数名和不同参数搭配时函数会有不同的含义: 举例说明: #include <stdio.h> ...

  6. C++默认参数与函数重载 注意事项

    一.默认参数在C++中,可以为参数指定默认值.在函数调用时没有指定与形参相对应的实参时, 就自动使用默认参数. 默认参数的语法与使用:(1)在函数声明或定义时,直接对参数赋值.这就是默认参数:(2)在 ...

  7. 面向对象程序设计-C++_课时17函数重载和默认参数

    函数重载,区别一是参数类型不同,二是参数个数不同. 默认参数可以多于1个,但必须放在参数序列的后部. 尽量不要用默认参数,会影响阅读 error C2668: “f”: 对重载函数的调用不明确 #in ...

  8. C++中关于重载默认构造函数与默认全部参数的构造函数的使用注意

    # include<iostream>using namespace std;class Time{public:                            //公用成员函数  ...

  9. C++ 函数的重载和参数默认值

    函数的重载和参数默认值视频教程 函数的重载注意事项: 只会根据三项内容进行重载:参数的个数.参数的类型.参数的顺序 参数默认值: 参数的默认值可以在函数的定义中也可以在函数的声明中,但不能同时有 从第 ...

随机推荐

  1. [android] 百度地图开发 (一).申请AK显示地图及解决显示空白网格问题

        近期做android百度地图,可是使用baidumapapi_v2_3_1.jar和libBaiduMapSDK_v2_3_1.so显示百度地图时总是遇到问题--仅仅显示网格而没有显示地图,网 ...

  2. Android Camera子系统之Linux C应用开发人员View

    Android Camera HAL通过V4L2接口与内核Camera Driver交互.本文从Linux应用开发人员的角度审视Android Camera子系统. V4L2应用开发一般流程: 1. ...

  3. 在Linux的终端中显示BMPString的内容

    在上一篇博文中,介绍了怎样在 Windows 的控制台界面下输出 BMPString 的内容,可是那里的方法在 Linux 下不适用.假设将那里的演示样例代码放到 Linux 下运行.输出的结果为乱码 ...

  4. poj2280--Amphiphilic Carbon Molecules(扫描线+极角排序+转换坐标)

    题目链接:id=2280">点击打开链接 题目大意:给出n个点的坐标.每一个点有一个值0或者1,如今有一个隔板(无限长)去分开着n个点,一側统计0的个数,一側统计1的个数,假设点在板上 ...

  5. CCEditBox/CCEditBoxImplAndroid

    #ifndef __CCEDITBOXIMPLANDROID_H__ #define __CCEDITBOXIMPLANDROID_H__ #include "cocos2d.h" ...

  6. WPF-MVVM-Demo

    MVVM The model-view-viewmodel is a typically WPF pattern. It consists of a view that gets all the us ...

  7. bzoj1026: [SCOI2009]windy数(传说你是数位DP)

    1026: [SCOI2009]windy数 题目:传送门 题解: 其实之前年少无知的时候好像A过...表示当时并不知道什么数位DP 今天回来深造一发... 其实如果对这个算法稍有了解...看到这题的 ...

  8. Pascal Script

    MsgBox http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_msgbox ExpandConstant http://www.jrs ...

  9. Mojo For Chromium Developers1

    Mojo For Chromium Developers Overview This document contains the minimum amount of information neede ...

  10. vue项目的一些最佳实践提炼和经验总结

    项目组织结构 ajax数据请求的封装和api接口的模块化管理 第三方库按需加载 利用less的深度选择器优雅覆盖当前页面UI库组件的样式 webpack实时打包进度 vue组件中选项的顺序 路由的懒加 ...