我没有什么C++经验。我的问题更多的是关于确认我是否通过一些查询正确思考。我试图理解代码,它有以下行:
string ltrim(const string &);
我看到了以下答案: 1. "std::string const &s"和"const std::string &s"有什么区别? 2. https://www.geeksforgeeks.org/stdstring-class-in-c/3. https://codereview.stackexchange.com/questions/32842/passing-parameters-by-reference
我知道按值调用和按引用调用的概念。
- 什么是"ltrim"?
在我看来,它是这里声明的函数名称,因为我知道C++没有具有此名称的预定义函数。我是否正确假设这意味着它是一个名为"ltrim"的"字符串"类型的函数,并且该函数具有参数"常量字符串类型"。
但是,通常我们有这样的功能:
void abc (int &a)
其中 a 是变量。变量是什么:
string ltrim(const string &);
因为"const"具有预定义的含义,而"字符串"是数据类型。参数中传递的变量是什么?
- 另外,如果没有变量,"&"在这里做什么。我理解通过引用调用一些 w.r.t C++,但我没有看到变量名称,我不知道用于传递什么。
我尝试在互联网上查找一些信息,但我无法找到一个用字符串解释这一点的地方。
什么是"ltrim"?
你的猜测是对的,ltrim
(左修剪)是一个接受const std::string&
作为参数并返回std::string
的函数。我们实际上不需要像您习惯看到的那样为参数命名,因为我们还没有使用该参数。我们只有在定义函数体后才会使用它,当前的代码行只是对函数的声明。
另外,如果没有变量,"&"在这里做什么。我理解 通过引用调用一些 w.r.t C++的东西,但我没有看到变量 名字,我不知道用什么来传递。
仅仅因为没有变量名称并不意味着函数不能请求对某种类型的引用。引用类型是类型的一部分,而不是变量名称的一部分,参数的名称是完全可选的:
void Foo(int, const int&, int*)
{
// stuff..
}
int main()
{
Foo(1, 2, nullptr);
}
只要Foo
不尝试访问参数,此代码就是完全合法的。不能,因为他们没有名字。
拆分声明和定义并在一个参数中而不是在另一个中为参数命名也是完全有效的:
void Foo(int);
int main()
{
Foo(1);
}
void Foo(int bar)
{
// stuff with 'bar'...
}
string ltrim(const string &);
这行代码声明名为ltrim
的函数存在,它接受未命名的const string&
参数,并返回一个string
。
令人困惑的是,C++不需要函数参数的名称!当需要保留接口但实现不再使用该参数时,您将看到这一点。
C++ 函数原型的目的是告诉编译器
- 函数的名称是什么,
- 其参数的类型是什么,以及
- 它返回的类型(如果有)。
这里的一个重要细节是上面的列表不包括参数的名称。例如,以下所有代码段声明相同的函数:
int myFunction(int a, double b);
int myFunction(int apples, double bananas);
int myFunction(int pizkwat, double zyzzyzyplyz);
此外,myFunction
的实际实现不需要使用此处给出的任何名称。例如,我们可以写
int myFunction(int snickerdoodle, double alfajores) {
// ... do something ... //
}
编译器会对此非常满意,即使上述原型都没有使用这些名称。
现在,对于一个奇怪的C++琐事:在C++中,可以声明具有没有名称的参数的函数。例如,此代码是完全合法的:
void doSomething(int) {
// This function takes in an integer. You can't call it without
// passing in that integer. However, this function has no way of
// referencing its argument, because it doesn't have a name!
}
您确实看到这在实践中使用。例如,重载后缀++
运算符需要声明一个名为operator++
的函数,该函数接收一个基本上从未使用过其值的int
。或者,您可能要重写派生类中的函数,而不需要使用提供的参数。
这意味着我们C++有三条规则:
规则一:忽略函数原型中的参数名称。
规则二:函数实现不必为其参数选择与其原型相同的名称。
规则三:参数甚至根本不需要有名称。
通过将这三个规则组合在一起,您有时会看到如下所示的内容:
int myFunction(int, double); // Prototype gives no names to arguments
int myFunction(int a, double b) {
// .. use parameters a and b ... //
}
在这里,函数原型没有为其参数命名,但这没关系!C++仍然学习有关函数的所有信息(名称、返回类型和参数类型)。这是合法的,因为规则一和规则三。在实际需要引用参数的实现中,这些参数被命名为a
和b
。由于规则二,这些参数现在具有名称这一事实很好。
因此,回到您的示例,函数原型
string ltrim(const string &);
意思是"我正在声明一个名为ltrim
的函数。它接受对const string
的引用,并返回一个string
。这完全等同于说
string ltrim(const string& toTrim);
或
string ltrim(const string& oompaLoompa);
ltrim
的实际实现,从外观上看,几乎可以肯定地命名了它的参数,以便它可以引用它并修剪字符串。
希望这有帮助!
该行声明一个名为ltrim
的函数,该函数返回一个string
并接受单个参数:对const string
的引用。
参数的名称是可选的。 在这种情况下,函数定义可能具有该参数的名称,但也可以省略该名称。 如果参数在函数定义中未命名,则无法在函数体中引用该参数,但如果您需要接受参数来实现某些接口但实际上不需要使用它,则它可能很有用。