自学内容网 自学内容网

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()就会被编译器标记成一个错误。


原文地址:https://blog.csdn.net/weixin_71738303/article/details/142677705

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!