成员名称和构造函数参数名称之间的冲突[重复]
Posted
技术标签:
【中文标题】成员名称和构造函数参数名称之间的冲突[重复]【英文标题】:Conflicts between member names and constructor argument names [duplicate] 【发布时间】:2012-10-01 03:19:40 【问题描述】:可能重复:Members vs method arguments access in C++
我的班级有一些成员,例如 x
、y
、width
和 height
。在它的构造函数中,我不会这样做:
A::A(int x, int y, int width, int height)
x = x;
y = y;
width = width;
height = height;
这真的没有意义,当使用 g++ 编译时,x
、y
、width
和 height
会变成奇怪的值(例如 -1405737648
)。
解决这些命名冲突的最佳方法是什么?
【问题讨论】:
呃,将a
附加到参数名称?
A::A (int xa, int ya, int widtha, int heighta)
如果要优雅,前置后缀a
,形成英文不定冠词:anX, aY, aWidth, aHaight
等。显然不能使用同一个标识符在同一范围内引用两个不同的变量。看我的回答。
嗯?我只是选择了“a”,因为它是我们字母表的第一个字母,我附加了它而不是前置它,因为它看起来更清晰。
我更喜欢给成员变量名称加上一个尾随下划线。即int x_;
【参考方案1】:
您可以使用相同名称的初始化列表:
A::A(int x, int y, int width, int height) :
x(x),
y(y),
width(width),
height(height)
如果您不想使用相同的名称,另一种方法是使用不同的名称。我想到了一些匈牙利符号的变化(我可能会对此感到讨厌):
//data members
int x_;
int y_;
int width_;
int height_;
//constructor
A::A(int x, int y, int width, int height) :
x_(x),
y_(y),
width_(width),
height_(height)
但是第一个建议没有错。
【讨论】:
17.4.3.1.2/1:以下划线开头的每个名称都保留给实现,用作全局命名空间中的名称。 @JohnDibling 为什么我认为这只适用于宏?哦,好吧......当我回顾我写的旧代码时,我想还有一件事我会讨厌......:D 匈牙利符号有什么问题? ;) 虽然,这实际上只是一个前缀名称,而不是匈牙利符号的变体。 @JohnDibling - 17.4.3.1.2 是“全局名称”。数据成员不是全局名称。尽管如此,我不会以下划线开头数据成员,只是因为。 @DavidHammen:我不认为那是什么意思。我认为该部分意味着 any 任何范围内以下划线开头的名称都由实现保留,实现将使用它作为全局名称。【参考方案2】:如果您必须在构造函数中使用赋值(而不是使用初始化器列表,这是首选),解决此问题的特定模式是使用this
指针,如下所示:
this->a = a;
【讨论】:
【参考方案3】:如果可能的话,最好通过初始化列表设置数据成员,在这种情况下,隐藏成员名称的参数没有问题。另一种选择是在构造函数的主体中使用this->foo = foo;
。 setter 也存在类似的问题,但现在您不能使用初始化列表解决方案。你被this->foo = foo;
卡住了——或者只是为参数和成员使用不同的名称。
有些人真的很讨厌影响数据成员的论点;多个编码标准明确表示永远不要这样做。其他人认为这种阴影,至少对于构造函数和设置者来说,是猫的喵喵叫。我记得读过一两个编码标准(但我不记得是哪个)将这种阴影指定为“应该”(但不是“应该”)的做法。
最后一个选择是在函数声明中使用阴影,以便向读者提示函数的作用,但在实现中使用不同的名称。
更新:什么是“阴影”?
#include <iostream>
void printi (int i) std::cout << "i=" << i << "\n";
int i = 21;
int main ()
printi (i);
int i = 42;
printi (i);
for (int i = 0; i < 3; ++i)
printi (i);
int i = 10;
printi (i);
printi (i);
i
、int i=10
的最内层声明遮蔽了在 for
语句中声明的变量 i
,进而遮蔽了在函数范围内声明的变量 i
,进而遮蔽了全局变量i
.
在手头的问题中,A
类的非默认构造函数的参数 x
、y
、width
和 height
隐藏了与这些参数同名的成员数据。
您的width=width;
什么也没做,因为参数width
隐藏(隐藏)了数据成员width
。当您有两个或多个在不同范围内声明的具有相同名称的变量时,获胜者始终是具有最内层范围的名称。通常,获胜的总是具有最内部范围的名称。
【讨论】:
您究竟将什么称为“阴影”? @Bane - 什么是“阴影”? Shadowing:(1)用于测试 CS 101 学生是否理解范围界定的酷刑装置。 (2) 当在某个范围声明的变量与在某个外部范围声明的变量同名时。 (3) 你对构造函数做了什么。 (4) 使用-Wshadow
编译时发现的潜在问题。 (5) 查看我的更新答案。【参考方案4】:
虽然您可以通过使用构造函数的初始化列表来避免该问题,但我建议遵循命名数据成员的约定,例如,结尾的_
或开头的m_
。否则你很可能会发生名称冲突,特别是如果你有名称为 x
和 y
的成员。
class A
public:
A(int x, int y, int width, int height) : x_(x), y_(y), with_(width), height_(height)
int x_;
int y_;
int width_;
int height_;
;
【讨论】:
我经常看到这个(尾随下划线)约定——你知道它的起源吗?感谢您的任何提示。 this-> 也是消除本地范围歧义的好方法。【参考方案5】:您可以只更改构造函数参数的名称。当你写
A::A(int x, int y, int width, int height)
x = x;
y = y;
width = width;
height = height;
然后您将 构造函数的参数分配给自己,而实际的实例变量未初始化,这就是您获得虚假值的原因。
我建议(并广泛使用)的一般解决方案是更改构造函数方法的参数名称:
A::A(int x_initial, int y_initial, int width_initial, int height_initial)
x = x_initial;
y = y_initial;
width = width_initial;
height = height_initial;
【讨论】:
是的,这就是我所做的,但我没有添加“_initial”,而是附加了“a”。 @Bane 那有什么问题? 嗯,这似乎是一个“丑陋”的解决方案,我认为它表明我对构造函数的理解有问题...... @Bane 你唯一缺少的是编译器不智能。以上是关于成员名称和构造函数参数名称之间的冲突[重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用与 C++ 标准允许的成员变量相同的名称为构造函数参数初始化成员变量? [复制]
Kotlin类与对象 ② ( 主构造函数 | 主构造函数定义临时变量 | 主构造函数中定义成员属性 | 次构造函数 | 构造函数默认参数 )