深入理解C++方法重载、内联与高级用法

2023年 11月 22日 107.7k 0

方法重载

你可能已经注意到,你可以在一个类中写多个构造函数,所有这些构造函数都有相同的名字。这些构造函数只在参数的数量和/或类型上有所不同。你可以对C++中的任何方法或函数做同样的事情。具体来说,你可以通过为具有不同数量和/或类型的参数的多个函数使用同一个名称来重载一个函数或方法。例如,在SpreadsheetCell类中,你可以将setString()和setValue()都重命名为set()。类定义现在看起来像这样:

export class SpreadsheetCell {
public:
    void set(double value);
    void set(std::string_view value);
    // 省略了一些内容以保持简洁
};

set()方法的实现保持不变。当你编写代码调用set()时,编译器会根据你传递的参数来确定调用哪个实例:如果你传递一个string_view,编译器会调用string_view实例;如果你传递一个double,编译器会调用double实例。这被称为重载解析。

你可能会试图对getValue()和getString()做同样的事情:将它们都重命名为get()。然而,这样做是不行的。C++不允许你仅基于方法的返回类型来重载一个方法名,因为在许多情况下,编译器无法确定你试图调用的是哪个方法实例。例如,如果方法的返回值没有被捕获在任何地方,编译器就没有办法知道你试图调用的是哪个方法实例。

基于const的重载

你可以基于const来重载一个方法。也就是说,你可以写两个具有相同名称和相同参数的方法,一个声明为const,另一个则不是。如果你有一个const对象,编译器会调用const方法;如果你有一个非const对象,它会调用非const重载。通常,const重载和非const重载的实现是相同的。为了避免代码重复,你可以使用Scott Meyer的const_cast()模式。

例如,Spreadsheet类有一个名为getCellAt()的方法,返回对非const SpreadsheetCell的引用。你可以添加一个const重载,返回对const SpreadsheetCell的引用,如下所示:

export class Spreadsheet {
public:
    SpreadsheetCell& getCellAt(size_t x, size_t y);
    const SpreadsheetCell& getCellAt(size_t x, size_t y) const;
    // 代码省

Scott Meyer的const_cast()模式将const重载实现为你通常会做的那样,并通过适当的转换将非const重载的调用转发给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(as_const(*this).getCellAt(x, y));
}

基本上,你首先使用std::as_const()(定义在中)将*this(一个Spreadsheet&)转换为const Spreadsheet&。接下来,你调用getCellAt()的const重载,它返回一个const SpreadsheetCell&。然后你用const_cast()将这个转换为非const SpreadsheetCell&。

有了这两个getCellAt()的重载,你现在可以在const和非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) };

在这种情况下,const重载的getCellAt()并没有做太多的事情,所以你通过使用const_cast()模式并没有赢得太多。然而,想象一下,如果const重载的getCellAt()做了更多的工作;那么将非const重载转发给const重载可以避免重复那些代码。

显式删除重载

重载的方法可以被显式删除,这使你能够禁止使用特定参数调用某个方法。例如,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()的操作将被编译器标记为错误。

Ref-Qualified方法

普通类方法可以在非临时和临时类实例上调用。假设你有以下类:

class TextHolder {
public:
    TextHolder(string text) : m_text { move(text) } {}
    const string& getText() const { return m_text; }
private:
    string m_text;
};

当然,毫无疑问,你可以在非临时实例的TextHolder上调用getText()方法。这里有一个例子:

TextHolder textHolder { "Hello world!" };
cout

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论