07  重载导致的二义性

问题:为什么一定要重载呢?重载能方便我们注重函数的功能,当参数类型不确定时,我们能很便捷的利用重载的机制达到目的。

重载注意点:二义性

看代码:

#include <cstdio>

void MyCout(int num)
{
printf("%d\n", num);
} void MyCout(char c)
{
printf("%c\n",c);
} void MyCout(float f)
{
printf("%f\n",f);
}
//MyCout@char*
void MyCout(char *str)
{
printf("%s\n", str);
} int main()
{ long lNum = ;
MyCout(lNum);
return ;
}

高亮代码会调用哪个函数?

断点,运行:100

#include <cstdio>

void MyCout(int num)
{
printf("%d\n", num);
} void MyCout(long num)
{
printf("%l\n", num);
} void MyCout(char c)
{
printf("%c\n",c);
} void MyCout(float f)
{
printf("%f\n",f);
}
//MyCout@char*
void MyCout(char *str)
{
printf("%s\n", str);
} int main()
{
/*int num = 100;
char c = 'a';
char *str = "I Love Mark";
float f = 1.0002;
MyCout(f);
MyCout(str);
MyCout(num);*/ short lNum = ;
MyCout(lNum);
return ;
}

代码测试,short long 不能匹配的时候,隐式的找int

unsigned long 会调用哪个?

重载的函数调用,它中间有个匹配,匹配有几大潜规则:

  1  精准匹配   2  提升匹配   3 类型转换匹配(当1和2都不能匹配时,尝试强转)  4  当匹配规则冲突时   当有了多个匹配时,二义性就出现了。

示例中 usigned long 它匹配的选择过多,产生二义性,所以报错。

如何消除二义性?改成精准匹配就行。

最好是根据业务需求来定义,不能写太多,也不能写太少。重载的时候最好不要用指针。比如(void*)。

再看示例:

#include <cstdio>

void f1(char c)
{ } void f1(long l)
{ } void f2(char * str)
{ } void f2(int * n)
{ } int main()
{
int n = ;
f1(n);
//f2(n);
return ;
}

运行:

1>------ 已启动生成: 项目: OverloadeDemo, 配置: Debug Win32 ------
1> main.cpp
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(34): error C2668: “f1”: 对重载函数的调用不明确
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(8): note: 可能是“void f1(long)”
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(3): note: 或 “void f1(char)”
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(34): note: 尝试匹配参数列表“(int)”时
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

这个int找不到精准匹配,也没找到提升匹配,开启强转类型,这里它可以强转为long,又可以强转为char,二义性出现,编译器晕了,糊涂了。

再看示例中的f2()

#include <cstdio>

void f1(char c)
{ } void f1(long l)
{ } void f2(char * str)
{ } void f2(int * n)
{ } int main()
{
/*int num = 100;
char c = 'a';
char *str = "I Love Mark";
float f = 1.0002;
MyCout(f);
MyCout(str);
MyCout(num);*/ int n = ;
//f1(n);
f2(n);
return ;
}

运行 :

1>------ 已启动生成: 项目: OverloadeDemo, 配置: Debug Win32 ------
1> main.cpp
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(35): error C2665: “f2”: 2 个重载中没有一个可以转换所有参数类型
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(18): note: 可能是“void f2(int *)”
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(13): note: 或 “void f2(char *)”
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(35): note: 尝试匹配参数列表“(int)”时
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

n的地址是一个unsgned int 类型,可以是char * 也可以是int* , 那么二义性产生。

为了避免二义性:要么精准匹配,要么强转类型。


08  默认实参

代码示例:

#include <cstdio>

void MyCout(int num,bool line)
{
printf("%d", num);
if(line)
printf("\n");
} void MyCout(char c , bool line )
{
printf("%c",c);
if(line)
printf("\n");
} void MyCout(char* str, bool line )
{
printf("%s",str);
if(line)
printf("\n");
} int main()
{
MyCout(,true);//参数true 不可缺少
return ;
}

这里MyCout(100,true)两个参数都要写上

代码一变:

#include <cstdio>

void MyCout(int num,bool line = true)
{
printf("%d", num);
if(line)
printf("\n");
} void MyCout(char c , bool line )
{
printf("%c",c);
if(line)
printf("\n");
} void MyCout(char* str, bool line )
{
printf("%s",str);
if(line)
printf("\n");
} int main()
{
MyCout(,true);//可以写
  MyCout(100);  //也可以不写
return ;
}

如果参数全部默认实参,那么,就可以什么参数也不写入:

#include <cstdio>

void MyCout(int num=,bool line=true)
{
printf("%d", num);
if(line)
printf("\n");
} void MyCout(char c , bool line )
{
printf("%c",c);
if(line)
printf("\n");
} void MyCout(char* str, bool line = true)
{
printf("%s",str);
if(line)
printf("\n");
} int main()
{
MyCout();
MyCout(,true);
MyCout("I Love Mark",true);
MyCout("I Love Mark");
return ;
}

当全部默认实参的时候,函数可以什么也不传递,当有一个默认实参的时候,这个参数可写入,也可以不写。

当全部默认实参的时候,也要注意二义性的产生:

#include <cstdio>

void MyCout(int num=,bool line=true)
{
printf("%d", num);
if(line)
printf("\n");
} void MyCout(char c , bool line )
{
printf("%c",c);
if(line)
printf("\n");
} void MyCout(char* str = "I Love Mark", bool line = true)
{
printf("%s",str);
if(line)
printf("\n");
} int main()
{
MyCout();
MyCout(,true);
MyCout("I Love Mark",true);
MyCout("I Love Mark",false);
MyCout("I Love Mark");
return ;
}

这里高亮的MyCout(),它可以匹配void MyCout(int num=50,bool line=true),又可以匹配void MyCout(char* str = "I Love Mark", bool line = true)。编译就报错。

要解决二义性有两种手段:1  使之唯一匹配   2  在调用时确定它的精确参数

08-2  补充

默认实参必需出现在整个参数的最右边,从右到左,最右边有了以后,左边的才能依次设置默认实参。


09 inlin函数

在函数之前加上关键字:inline

在编译时展开,好处:不会新建栈,只将代码展开。运行效率会大大提升,生成的体积会膨胀。

内联并不是百分百的形成,会根据编译器的判断来完成,它有几个判断的标准:1  栈的使用

代码的鼓胀常见于以后学习的模版中,泛型中。代码鼓胀会使得调试困难。

宏替换和inline的区别在于:inline会有类型的检测。

09-2  inline 函数展开的情况 ( 补充)

内联形成的重要标准:栈的使用。

复杂度:

有人说10行以内的代码或许内联能100之100成功,但如果10行代码,有9行是调用其它函数呢,这个不好说了。这是个扯蛋的说法。

大量的inline会使得程序编译时间加长。

小结:inline内联能成则成,交给编译器。


10 C++风格  类型转换 

隐式转换是有风险的,我们有时把隐式转换,写成强制的转换。比如:在算除法,和百分比的的时候等。

上面是C语言的风格,C++的类型转换是什么样子呢?

static_cast<int> 它不是强制转换,是表示转换   (常见于:基类指针 向派 生类指针 之间的一个转换)

const_cast<>  特定情况下使用,它可以使const变成非const。它的作用是用来移除对象的常量性,但还是不能修改内容;不实现const版本。具体有什么用?重载时,它可以用来作参数的匹配, 使得你语法上不会出现错误。常见于指针或者引用上。

reinterpret_cast<>    强制转换   二进制层面的强制转换  不建议使用

强制转换为一个地址。危险操作,不建议使用。

还有一个转换符:dynamic_cast<>  名称推导转换  写大型框架的时候常见。

转换符4个:   1 static_cast<>    2  const_cast<>     3  reinterpret_cast<>   4   dynamic_cast<>

举例了C语言 void*  交换 数据  与C++  里面函数重载的小示例。

补充:

1  风格,头文件的风格:适合C++的,就是C++风格

2   C风格的转换,不管怎么样,都转换成功,简单暴力

3   C++风格拆分为几个,有相对安全的static_cast,有完全不安全的reiterpret_cast,但还是开放,以适用更多的场景。


PoEdu - C++阶段班- Lesson07 To Lesson10_C to C++的更多相关文章

  1. PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天

    PoEdu - C++阶段班[Po学校]- 第6天 课堂选择题目: 1  关于转换构造函数  ClassDemo demo = 1;  调用转换构造函数 2  关于拷贝赋值函数  demo =2; 首 ...

  2. PoEdu - C++阶段班【Po学校】- Lesson02_类与对象_第4天

    复习:上节作业讲解 注意点: 设计SetString()的时候,要注意重置原来的空间. char * SetString(const char *str) { _len = strlen(str); ...

  3. PoEdu - C++阶段班【Po学校】- 第3天

    引用 C中指针的功能强大,使用起来繁杂,因为指针要控制的东西太多:有指针的类型,指针的解引用,指针空间内的值,它本身是有空间的,有自己的地址等.指针也是强大的,比如:我们要在函数之内,修改方法之外的值 ...

  4. PoEdu - C++阶段班- Lesson02_C to C++

    1  原生bool类型 c++里面的bool类型才是真正原生的true和faul,比如常见的大写的"BOOL",它就不是原生的. 原生的与非原生的bool,它们的区别: 详细说下原 ...

  5. PoEdu - C++阶段班【Po学校】- 第1课

    1 C++开讲 C ++  伟大的编程语言:能提高程序运行效率,节约更多的资源,"正确的使用C++,能够抑制全球变暖问题". 2 C++能力雷达图 通过 1效率 2灵活度 3 抽象 ...

  6. PoEdu- C++阶段班【Po学校】-Lesson03_构造函数精讲 - 第5天

    复习构造函数:1  与类同名   2  没有返回值   3  自动生成    4  手动后,不会自动生成    5  不在特定的情况下,不会私有  新建 类   两种方法示范   其一:在vs中选择类 ...

  7. PoEduo - C++阶段班【Po学校】-Lesson03-5_运算符重载- 第7天

    PoEduo - Lesson03-5_运算符重载- 第7天 复习前面的知识点 空类会自动生成哪些默认函数 6个默认函数    1  构造  2  析构   3  赋值  4 拷贝构造  5 oper ...

  8. [福大软工] Z班 团队Beta阶段成绩汇总

    Beta敏捷冲刺得分 队伍名 1 2 3 4 5 总分 Dipper 10 10 10 10 10 50 SWSD 9 9 9 9 7 43 五成胜算 10 10 10 10 10 50 人月神教 0 ...

  9. 福州大学软件工程1816 | W班 团队Alpha阶段成绩汇总排名(第9、10次作业)

    写在前面 汇总成绩排名链接 1.作业链接 第九次作业--项目Alpha冲刺(团队) 第十次作业--事后诸葛亮(团队) 2.评分准则 本次作业包括现场Alpha答辩评分(映射总分为100分)+博客分(总 ...

随机推荐

  1. access remote libvirtd

    访问远程libvirtd服务因为是在一个可信环境中运行,所以可以忽略安全方面的操作,步骤如下:(1)更改libvirtd配置    1.1 更改/ect/sysconfig/libvirtd文件,打开 ...

  2. Glide 下载Gif文件

    之前做了一个类似朋友圈里的查看大图功能,现在也要加上保存功能. 保存图片有很多思路,可以从imageview里提取bitmap,可以用url下载到本地.imageview提取的话,gif图就会变成一张 ...

  3. JVM参数(一)JVM类型以及编译器模式

    现在的JVM运行Java程序(和其它的兼容性语言)时在高效性和稳定性方面做的非常出色.自适应内存管理.垃圾收集.及时编译.动态类加载.锁优化——这里仅仅列举了某些场景下会发生的神奇的事情,但他们几乎不 ...

  4. PHP 开发的 API 多版本管理实践

    遇到的情况 本文针对移动互联网客户端需要兼容旧版的情况,强制升级到最新版本的 app 不在讨论之列. 在 bugtags.com 项目中,我们的版本遵循下面规范.1.0.1大功能.小更新.bug 修正 ...

  5. 通过DOM节点操作来获取表单信息

    这是之前突发奇想地用dom节点的关系来操作表单的故事.. 事情的经过是这样的,大概就是一个平台注册后有留言功能,管理员登录之后可以对这些留言进行回复.这个页面呢,就是通过foreach获取到数据库里的 ...

  6. winform建立非矩形窗体

    非规则窗体可能会需要加的功能代码: 1:因为没有了最上边的标题栏,所以需要加窗体鼠标拖动功能,在Form里面加如下代码: #region 移动窗体 // 移动窗体 const int WM_NCLBU ...

  7. js动态增加html页面元素

    问题:   <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2 ...

  8. HDU5878

    http://acm.hdu.edu.cn/showproblem.php?pid=5878 给出你一个数字,让你求出大于这个数字n并且是形如2^a*3^b*5^c*7^d的最小的数: 就是用打表法求 ...

  9. Appium for Mac 环境准备篇

    之前写过一篇Appium for windows的文章,因为是09年的T400,启动Android模拟器的时候死机三次,那就公司申请台Macbook air吧,15寸的Macbook Pro实在太重了 ...

  10. javascript--关于错误

    错误是一定会发生,所以语言都会有自己的错误处理机制.javascript的错误处理机制,关乎throw.try.catch. try 语句允许我们定义在执行时进行错误测试的代码块. catch 语句允 ...