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

然而,getText()也可以在临时实例上调用:
cout << TextHolder{ "Hello world!" }.getText() << endl;cout << move(textHolder).getText() << endl;你可以通过添加所谓的ref-qualifier来明确指定可以在哪种类型的实例上调用某个方法,无论是临时的还是非临时的 。如果一个方法只应该在非临时实例上调用 , 在方法头后加上&限定符 。类似地,如果一个方法只应该在临时实例上调用 , 在方法头后加上&&限定符 。
下面修改后的TextHolder类实现了带有&限定符的getText(),通过返回对m_text的引用 。而带有&&限定符的getText()返回m_text的右值引用,这样m_text就可以从TextHolder中移动出来 。如果你想从临时TextHolder实例中检索文本,这可能会更有效率 。
class TextHolder {public:TextHolder(string text) : m_text { move(text) } {}const string& getText() const & { return m_text; }string&& getText() && { return move(m_text); }private:string m_text;};假设你有以下调用:
TextHolder textHolder { "Hello world!" };cout << textHolder.getText() << endl;cout << TextHolder{ "Hello world!" }.getText() << endl;cout << move(textHolder).getText() << endl;那么第一次调用getText()会调用带有&限定符的重载,而第二次和第三次调用则会调用带有&&限定符的重载 。
内联方法C++允许你建议调用一个方法(或函数)时,不应该在生成的代码中实际实现为调用一个单独的代码块 。相反,编译器应该将方法的主体直接插入到调用该方法的代码中 。这个过程被称为内联,希望这种行为的方法被称为内联方法 。
你可以通过在方法定义中的名字前放置inline关键字来指定一个内联方法 。例如 , 你可能想让SpreadsheetCell类的访问器方法成为内联的,这种情况下 , 你会这样定义它们:
inline double SpreadsheetCell::getValue() const {m_numaccesses++;return m_value;}inline std::string SpreadsheetCell::getString() const {m_numAccesses++;return doubleToString(m_value);}这向编译器提供了一个提示,用实际的方法体替换对getValue()和getString()的调用,而不是生成代码来进行函数调用 。请注意,inline关键字只是一个提示给编译器 。如果编译器认为这会影响性能 , 它可以忽略它 。
有一个注意事项:内联方法(和函数)的定义必须在每个调用它们的源文件中都可用 。如果你想一下,这是有道理的:如果编译器看不到方法定义 , 它怎么能代替方法的主体呢?因此,如果你编写内联方法,你应该将这些方法的定义放在类定义所在的同一个文件中 。
注意,高级C++编译器不要求你将内联方法的定义放在类定义的同一个文件中 。例如,Microsoft Visual C++支持链接时代码生成(LTCG),它会自动内联小的函数体,即使它们没有被声明为inline,即使它们没有定义在类定义的同一个文件中 。GCC和Clang也有类似的功能 。
在C++20模块之外,如果一个方法的定义直接放在类定义中,即使没有使用inline关键字,该方法也隐式地被标记为内联 。使用C++20中从模块导出的类时,情况并非如此 。如果你希望这些方法是内联的,你需要用inline关键字标记它们 。这里有一个例子:
export class SpreadsheetCell {public:inline double getValue() const {m_numAccesses++;return m_value;}inline std::string getString() const {m_numAccesses++;return doubleToString(m_value);}// 省略了一些内容以保持简洁}注意,如果你在调试器中单步执行一个被内联的函数调用,一些高级C++调试器会跳转到内联函数的实际源代码,给你造成了函数调用的假象 , 而实际上代码是内联的 。许多C++程序员在不理解将一个方法标记为内联的后果时,就使用了内联方法语法 。将一个方法或函数标记为内联只是给编译器一个提示 。编译器只会内联最简单的方法和函数 。如果你定义了一个编译器不想内联的内联方法 , 它会默默地忽略这个提示 。现代编译器会在决定内联一个方法或函数之前 , 考虑诸如代码膨胀等指标,并且不会内联任何不划算的东西 。
默认参数在C++中 , 与方法重载类似的功能是默认参数 。你可以在原型中为函数和方法参数指定默认值 。如果用户为这些参数提供了参数,那么默认值将被忽略 。如果用户省略了这些参数,将使用默认值 。不过,有一个限制:你只能为从最右边的参数开始的连续参数列表提供默认值 。否则,编译器将无法将缺失的参数与默认参数匹配 。默认参数可用于函数、方法和构造函数 。例如,你可以为Spreadsheet构造函数中的宽度和高度分配默认值,如下所示:


推荐阅读