使用相同的参数名称和成员名称是否有效

Is using same parameter name and member name valid

本文关键字:是否 有效 成员 参数      更新时间:2023-10-16

假设我想将参数变量复制到成员变量,这是有效的C++吗:

struct Struct {
  Struct(const T& value) : value(value) {}
  T value;
};

(更新:它可以在Visual Studio中工作,但仍然可能依赖于编译器((预期问题:你为什么需要这个?答:宏制作目的(

这确实是有效的代码,与其他答案一样,我会警告您应该非常小心地使用它,因为它可能会令人困惑,并可能导致难以维护的代码。

那么为什么会这样呢?如果我们考虑您的构造函数:

Struct(const T& value) : value(value) {}
                         ^     ^
                         1     2    

12在不同的范围内进行评估。因此,我们需要查看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;
};