当前位置: 首页 > article >正文

C++学习笔记----8、掌握类与对象(二)---- 成员函数的更多知识(2)

3、成员函数重载

        你已经注意到在类中可以写多个构造函数,所有的都有同样的名字。这些构造函数的不同仅仅在于其参数的数目与/或类型。在c++中任何成员函数或函数可以做同样的事情。特别地,可以重构一个函数或成员函数名,通过使用它来用于多个函数,只要参数的数目和/或类型不同。例如,在SpreadsheetCell类中,可以将setString()与setValue重命名为set()。类定义现在看起来像这样:

export class SpreadsheetCell
{
public:
    void set(double value);
    void set(std::string_view value);
    // Omitted for brevity
};

        set()成员函数的实现保持不变。当写代码调用set()时,编译器决定调用哪个实例,是基于传入的参数:如果传入参数是string_view,编译器会调用string_view实例;如果传入的是一个double,编译器为调用double实例。这叫做调用重载解析。

        你可能会想对getValue()与getString()做同样的事情:把它们重命名为get()。然而,这却不好使。c++不允许只基于返回类型来重载一个成员函数,因为在很多情况下编译器无法决定调用成员函数的实例。例如,如果成员函数的返回值没有被获取,编译器就不知道你想调用哪个成员函数的实例。

3.1、基于const重载

        可以基于const重载成员函数。也就是说,可以写两个同名同参数的成员函数,一个声明为const,而另一个不是。如果你有一个const对象编译器调用const成员函数,如果你有一个non-cost对象它会调用non-const重载。写这校招的两个重载成员函数可能会带来代码重复,因为,通常情况下,const与non-const重载的实现是一样的。你知道的,应该尽可能地避免代码重复,即使是只有几行。要遵循我们以前讨论过的DRY(不要重复自己)原则,使以后的代码维护容易些。例如,想像一下,几个月或者几年后,需要对重复代码做一点小小的变更。当这样做的时候,需要记住要对所有出现重复代码的地方进行同样的修改。是不是很烦人?

        下面一节会提供两个解决方案来避免代码重复,当写这样重载成员函数的时候。

3.1.1、Scott Meyers的const_cast模式

        为了避免代码重复,可以使用Scott Meyers的const_cast()模式。例如,Spreadsheet类有一个叫做getCellAt()的成员函数返回一个reference-to-non-const给到SpreadsheetCell。可以加一个const重载返回一个reference-to-const给到SpreadsheetCell,如下:

export class Spreadsheet
{
public:
    SpreadsheetCell& getCellAt(std::size_t x, std::size_t y);
    const SpreadsheetCell& getCellAt(std::size_t x, std::size_t y) const;
    // Code omitted for brevity.
};

        Scott Meyer的const_cast()模式应用const重载就像你通常做的那样,通过传递调用给const重载使用合适的转化来实现non-const重载,如下:

const SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) const
{
    verifyCoordinate(x, y);
    return m_cells[x][y];
}

SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
{
    return const_cast<SpreadsheetCell&>(as_const(*this).getCellAt(x, y));
}

        模式首先使用std::as_const()将*this(一个Spreadsheet&)转化为一个const Spreadsheet&。接着,调用getCellAt()的const重载,它返回一个const SpreadsheetCell&。然后用const_cast()将其转化为一个non-const SpreadsheetCell&。

        有了这两个getCellAt()重载,现在可以对const与non-const Spreadsheet对象调用getCellAt()了:

Spreadsheet sheet1 { 5, 6 };
SpreadsheetCell& cell1 { sheet1.getCellAt(1, 1) };
const Spreadsheet sheet2 { 5, 6 };
const SpreadsheetCell& cell2 { sheet2.getCellAt(1, 1) };

3.1.2、私有的辅助成员函数

        另一个避免代码重复的选项是在实现const与non-const重载时用non-const返回类型做一个private const辅助成员函数。const与non-const重载成员函数都调用这个辅助函数。例如,对于上一节中的getCellAt()重载,可以添加一个getCellAtHelper()如下:

export class Spreadsheet
{
public:
    SpreadsheetCell& getCellAt(std::size_t x, std::size_t y);
    const SpreadsheetCell& getCellAt(std::size_t x, std::size_t y) const;
    // Code omitted for brevity.

private:
    SpreadsheetCell& getCellAtHelper(std::size_t x, std::size_t y) const;
};

        下面是实现:

SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
{
    return getCellAtHelper(x, y);
}

const SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) const
{
    return getCellAtHelper(x, y);
}

SpreadsheetCell& Spreadsheet::getCellAtHelper(size_t x, size_t y) const
{
    verifyCoordinate(x, y);
    return m_cells[x][y];
}

3.2、显式删除重载

        重载成员函数可以被显式删除,这样就可以禁止使用特别的参数来调用成员函数。例如,SpreadsheetCell类有一个成员函数setValue(double)可以被调用如下:

SpreadsheetCell cell;
cell.setValue(1.23);
cell.setValue(123);

        第三行,编译器将整数(123)转化为double,然后调用setValue(double)。如果,基于某种原因,你不想setValue()用整数调用,可以显式地删除setValue()的整型数重载:

export class SpreadsheetCell
{
public:
    void setValue(double value);
    void setValue(int) = delete;
};

        有了这个改变,意图用整型数调用setValue()就会被编译器标记成一个错误。


http://www.kler.cn/news/333645.html

相关文章:

  • 【Mybatis篇】Mybatis的关联映射详细代码带练 (多对多查询、Mybatis缓存机制)
  • 【Java的SPI机制】Java SPI机制:实现灵活的服务扩展
  • 4.人员管理模块(开始预备工作)——帝可得管理系统
  • (16)MATLAB仿真Nakagami-m分布1
  • 高并发领取优惠卷加锁的坑!(事务边界问题/事务失效问题)
  • leetcode42:接雨水
  • Linux驱动开发(速记版)--设备模型
  • WPF下使用FreeRedis操作RedisStream实现简单的消息队列
  • Vue+NestJS项目实操(图书管理后台)
  • 分治算法(1)_颜色分类
  • 初识数据结构--时间复杂度 和 空间复杂度
  • Linux 之 安装软件、GCC编译器、Linux 操作系统基础
  • TX-LCN框架 分布式事务
  • 【案例】平面云
  • 第十五讲-选择控件QComboBox
  • 插画共享系统小程序的设计
  • 关于cefsharp访问iqiyi.com显示403 Forbidden解决办法(2种方法)
  • C++:图的最小生成树
  • 基于微信小程序的四六级词汇+ssm(lw+演示+源码+运行)
  • PYTHON实现HTTP request的一些有用的函数