使用相同的参数名称和成员名称是否有效
Is using same parameter name and member name valid
假设我想将参数变量复制到成员变量,这是有效的C++吗:
struct Struct {
Struct(const T& value) : value(value) {}
T value;
};
(更新:它可以在Visual Studio中工作,但仍然可能依赖于编译器((预期问题:你为什么需要这个?答:宏制作目的(
这确实是有效的代码,与其他答案一样,我会警告您应该非常小心地使用它,因为它可能会令人困惑,并可能导致难以维护的代码。
那么为什么会这样呢?如果我们考虑您的构造函数:
Struct(const T& value) : value(value) {}
^ ^
1 2
1
和2
在不同的范围内进行评估。因此,我们需要查看C++初始化基和成员12.6.2
标准部分的草案,并查看一些语法:
ctor-initializer:
: mem-initializer-list
mem-initializer-list:
mem-initializer ...opt
mem-initializer , mem-initializer-list ...opt
mem-initializer:
mem-initializer-id ( expression-listopt )
mem-initializer-id braced-init-list
消化完之后,我们看到1
实际上是一个 mem-initializer-id,2
是一个表达式列表选择,我们可以分别转到第 2 段和第 12 段。第2段说:
在 mem-initializer-id 中,将在构造函数类的作用域中查找初始非限定标识符,如果在该作用域中找不到,则会在包含构造函数定义的作用域中查找该标识符。[...]
因此,1
将首先在课堂上查找,而我们可以从第12段中看到:
内存初始值设定项的表达式列表或大括号初始化列表中的名称在为其指定了 mem 初始值设定项的构造函数的范围内计算。
2
将在构造函数的范围内查找。因此,1
将首先找到成员变量并停止查找,而2
将在构造函数中查找并找到参数。这也意味着,如果要引用表达式列表中的成员变量,则必须使用 this->。
毫无疑问,它是完全有效的、符合标准的代码。
Struct(const T& value) : value(value) {}
^^^^^ this is argument
^^^^^ this is the member
现在的问题是:这是好的做法吗?在我看来,没有。我希望我的数据成员遵循不同但一致的命名约定,例如数据成员总是以_
开头。所以我更喜欢这个:
Struct(const T& value) : _value(value) {}
其中_value
是数据成员。您可以遵循任何命名约定 - 只需确保您保持一致即可。
请注意,在代码变量中,函数、类或任何标识符不应以双下划线(如 __value
(或单下划线后跟大写字母(如 _Value
(开头 — 此类名称是为实现保留的。
C++标准允许的,但请考虑在初始化成员后希望在函数中执行更多工作的情况。例如,使用 3
代替一些更有意义的计算:
class Foo
{
public:
int bar;
Foo(int bar) : bar(bar) { bar = 3; }
};
函数中的赋值更改参数 bar
的值,而不是成员bar
的值。在您的示例中不会发生这种情况,因为您使用 const
声明了参数。因此,如果您确定始终使用 const
声明参数,您将受到保护。但请考虑一个更复杂的场景:
class Foo
{
public:
int bar;
int baz;
void AuxiliaryFunction() { bar = 3; }
Foo(const int &bar) : bar(bar)
{
AuxiliaryFunction();
baz = bar;
}
};
在此示例中,成员bar
通过构造函数中调用的另一个函数获得一些值。然后赋值baz = bar;
可能旨在复制成员bar
,但它实际上复制参数bar
。
因此,虽然这是合法C++,但应明智地使用它。
是的。它确实可以编译。对于编译器来说,哪个value
哪个是哪个没有歧义。
#include <iostream>
using namespace std;
template <typename T>
struct Struct {
Struct(const T & value) : value(value) {}
T value;
};
int main() {
Struct<int> T(1);
// your code goes here
return 0;
}
http://ideone.com/gPyBK6
但是在多次声明的情况下,这对程序员来说并不容易破译。它确实有效,因为对于编译器来说,参数屏蔽了成员函数,所以value(value)
中的第二个value
是参数,但由于只有成员和祖先类可以在value(value)
的左侧,它确实在这里引用了成员。
非常棘手,使调试和维护复杂化。
这是有效的,但在某些圈子里是不明智的,包括我的圈子。
从某种意义上说,它是有效的,因为成员变量将由参数根据需要正确设置。 执行初始值设定项列表后,成员将被隐藏。 对value
的任何引用都将访问该参数。 这可能是一件坏事。
出于两个原因,这是不明智的。 首先,可维护性和混乱。 参数和成员变量具有相同的名称是不常见的。 正因为如此,大多数程序员将不得不停下来思考它意味着什么。 毕竟,你做到了。 请记住,代码首先是为程序员编写的,其次是为编译器编写的。 易于理解的代码比难以理解的代码要好得多。 在代码审查中,我会以这些理由拒绝此代码。
其次,在大多数情况下,成员隐藏可能是一个问题。
我建议提出一个理智的命名方案并坚持下去。 "Sane"表示参数永远不能与成员变量同名。 例如,在我的命名方案中,成员变量总是以 m
开头 -- 参数从不前置。 因此,在此方案中,您的代码将变为:
struct Struct {
Struct(const T& value) : mValue(value) {}
T mValue;
};
使用这个方案,没有人对这里发生的事情感到困惑,也没有人需要问StackOverflow"这是合法的吗?
它是有效的。但是有一点警告:更改参数名称和代码是未定义的行为。
template <typename T>
struct Struct {
Struct(const T & argument) : value(value) {}
T value;
};
<</div>
div class="answers"> 这是有效的,但正如甚至需要问这个问题所证明的那样,可能会令人不快和困惑。
长期存在的问题是想出两个不同的名称来描述同一件事。
我喜欢这样做(但有些人讨厌它(:
struct Struct {
Struct(const T& newValue) : value(newValue) {}
T value;
};
- 如果变量名称不跟在 char* 后面,const char* 是否有效?
- 钳制迭代器是否有效
- 检查由括号、方括号和大括号组成的一组方括号是否有效?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 模板签名解析为 void(void) 被 GCC 拒绝;这是否有效C++?
- 我如何知道作为参数的size_t在函数中是否有效?
- 我的运算符重载是否有效<<(流插入)左操作数不是 ostream
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 此递归模板类型定义是否有效C++?
- 将 C 函数转换为 C++ 以检查数字是否有效
- 函数参数的名称与调用函数时使用的变量相同是否有效?
- 如何检查输入是否有效?
- 如何检查用户的输入是否有效以及我正在寻找的数字?
- 在函数中按值传递 unordered_map/unordered_set 是否有效? C++
- 如何检查isupper(cstr)是否有效?
- 将 std::transform 与 std::back_inserter 一起使用是否有效?
- 只需要知道我在c ++中打印模式的方式是否有效,或者有另一种方法可以有效地做到这一点
- 如何检查字符串格式在读取C++文本文件时是否有效?
- 在 c++ 中将对象设置为等于同一类的构造函数是否有效?
- 创建加密安全密码.并验证它是否有效