PoEdu培训 C++班 第二课 C过度到C++(2)
文章类别: 培训笔记 0 评论

PoEdu培训 C++班 第二课 C过度到C++(2)

文章类别: 培训笔记 0 评论

C过度到C++ (2)

接上一篇博文

为什么要有重载

它可以让我们很方便的进行一系列调用
它解决了因为数据类型不同而引发的一些编写代码方面的问题

比如, 代码复用问题
比如, 大量代码重复仅仅因为参数类型不同问题.

重载的匹配

// 重载例子
#include <cstdio>

void HadesCout(int num)
{
    printf("%d", num);
}

void HadesCout(char* szStr)
{
    printf("%s", szStr);
}

void HadesCout(char c)
{
    printf("%c", c);
}

void HadesCout(double dNum)
{
    printf("%f", dNum);
}

int main()
{
    HadesCout("Hello C++\n");
    HadesCout(100);
    HadesCout(10.0);
    HadesCout('H');
    return 0;
}
我们以例子来看

当我们执行 long i = 100; HadesCout(i); 语句
我们没有 long参数 的重载方法, 那么程序会调用谁?

会调用 int 参数的方法

我们加上一个 long 参数的方法, 如下:

void HadesCout(long num)
{
    printf("%ld", num);
}

当我们执行 short i = 100; HadesCout(i); 语句
我们没有 short参数 的重载方法, 那么程序会调用谁?

会调用 int 参数的方法

当我们执行 unsigned long i = 100; HadesCout(i); 语句
我们没有 unsigned long参数 的重载方法, 那么程序会调用谁?

会编译不通过.

为什么会这样?

在重载的实现过程中, 会有一个匹配的过程.
匹配的时候是有规则的.
发生错误是因为它并没有一个匹配的规则.

匹配规则类别:  
  1. 精准匹配
  2. 提升匹配

    • char 可提升至 int
    • float 可提升至 double
    • ......
  3. 类型转换匹配

    • int 可转换为 unsigned int
    • ......
  4. 当匹配的规则冲突时(有多个匹配), 就会出现二义性.
建议

重载的二义性

// 举个例子
#include <iostream>

using namespace std;

void f1(long lVal) {}
void f1(char cVal) {}
void f1(char* pcVal) {}
void f1(int* piVal) {}

int main()
{
    int iNum = 100;
    // 猜猜结果?
    f1(iNum);
    f2(iNum);
}

// 两句话都会报错
// 因为首先, f1没有精准匹配结果

如何解决?
新增精准匹配
类型转换后进行匹配

默认实参(Default Argume)

#include <cstdio>

void HadesCout(int iNum, bool isPrintCrLf = true)
{
    printf("%d", iNum);
    if (isPrintCrLf)
        printf("\n");
}

void HadesCout(char cVal, bool isPrintCrLf = true)
{
    printf("%c", cVal);
    if (isPrintCrLf)
        printf("\n");
}

void HadesCout(char* szVal, bool isPrintCrLf)
{
    printf("%s", szVal);
    if (isPrintCrLf)
        printf("\n");
}

int main()
{
    HadesCout(100);
    HadesCout("Hello Hades", true);
    HadesCout('H', false);
    return 0;
}

默认实参的二义性

我们将上面的代码稍作修改.

#include <cstdio>

void HadesCout(int iNum = 100, bool isPrintCrLf = true)
{
    printf("%d", iNum);
    if (isPrintCrLf)
        printf("\n");
}

void HadesCout(char* szVal = "Hades Studio", bool isPrintCrLf = true)
{
    printf("%s", szVal);
    if (isPrintCrLf)
        printf("\n");
}

int main()
{
    // 猜猜结果?
    HadesCout();
    return 0;
}

此时调用 HadesCout 就会出错, 因为它产生了二义性.

二义性

在调用函数时, 编译器无法找到与之唯一匹配的函数, 就会造成二义性.

解决方法

内联函数

inline关键字可以把函数做成内联函数.
当函数被成为内联函数后, 在调用的时候就会展开(代码).
不会新建栈空间来进行call

优缺点:

标记inline关键字的函数并不是100%会成为内联函数
它会根据编译器的判断来完成

不加 inline 则不会成为内联函数.
只有加了 inline 关键字, 编译器才会尝试去讲函数变为内联函数.

判定标准:

inline会有类型的检测, 内联函数还是一个函数
这是inline和define最大的不同, 替换终究只是替换

代码膨胀

仅作了解

在预处理的时候, 我们会生成许多代码展开
    比如,
    #include会被展开
    #define会被展开
    inline会被展开
    泛型会被展开
    ....
在代码膨胀之后, 在C++中会造成一些影响.
比如在调试的时候, 出现了某个编译器生成的代码的错误, 但是我们并没有写这个函数.

类型转换

在C语言中, 有如下转换方式

在C++中, 我们的转换方式如下

  1. 隐式转换, C语言风格的强制转换
#include <iostream>

int main()
{
    // 会产生隐式转换
    int iNum1 = 1.0003;
    // 所以我们经常会进行强制转换(C模式/C风格)
    int iNum2 = (int)1.0003;
    return 0;
}
  1. static_cast, C++风格式的转换

    • C++ 模式/C++ 风格的转换
    • 注意, 它不是强制转换
    • 它只是表示转换
    • 经常用于基类指针指向派生类指针时使用
#include <iostream>

int main()
{
    int iNum3 = static_cast<int>(1.0003);

    return 0;
}
  1. const_cast, 常量性转换

    • 它在特定情况下使用
    • 可以使 const 的变为 非const 的.
    • 也就是说, 它可以移除对象的常量性.
    • 但是转换之后, 还是不能修改内容.
    • 主要适用于

      • 参数的匹配
      • 消除语法上的错误
      • 用来不实现const版本
#include <iostream>

int main()
{
    // 此处无举例...
    return 0;
}
  1. reinterpret_cast, 强制转换

    • 真正的强制转换
    • 基于二进制层面的转换, 相当于拿指针进行拷贝
    • 尽量不要使用
    • 非常危险!!!
#include <iostream>

int main()
{
    int iNum4 = 10;
    char* szStr = "Hades Studio";
    iNum4 = reinterpret_cast<int>(szStr);
    // 转换过后会, num变为szStr指向的地址..

    int* pNum = nullptr;
    // 不能够编译通过
    // char* pSz = pNum;
    // 不能够编译通过
    // char* pSz = static_cast<char*>(pNum);
    // 可以使用
    char* pSz = reinterpret_cast<char*>(pNum);

    return 0;
}
  1. dynamic_cast, 类型推导转换

    • 仅作了解
#include <iostream>

int main()
{
    // 此处无例子
    return 0;
}

补充

static_cast, dynamic_cast, reinterpret_cast 和 (char)int 类型的强制转换

我们有2种风格的强制转换
(char)int 这种为 C风格的转换

它是比较暴力的
有安全的, 也有非安全的.
不管怎么样都会转换成功!
简单, 暴力

static_cast

相对来说是安全的

dynamic_cast

暂时不表

reinterpret_cast

非常危险, 是不安全的.
它是开放的, 并不禁止这种转换行为.

未完待续

如有错误,请提出指正!谢谢.

回复