为什么不能在 C++ 中重新定义类中的类型名称?
根据本书 C++ Primer 部分,7.4.1 Type Names Are Special:
According to the book C++ Primer section, 7.4.1 Type Names Are Special:
通常,内部作用域可以从外部作用域重新定义名称,即使该名称已在内部作用域中使用.但是,在类中,如果成员使用外部作用域中的名称并且该名称是类型,则该类随后可能不会重新定义该名称.
Ordinarily, an inner scope can redefine a name from an outer scope even if that name has already been used in the inner scope. However, in a class, if a member uses a name from an outer scope and that name is a type, then the class may not subsequently redefine that name.
相应地,例如:
typedef double Money;
class Account {
public:
Money balance() { return bal; }
private:
typedef double Money;
Money bal;
};
int main() {
typedef double Money;
Money asset;
typedef double Money;
return 0;
}
当你编译上面的例子时,它会报错:
When you compile the example above, it will complain:
a.cc:6:24: error: declaration of ‘typedef double Account::Money’ [-fpermissive]
typedef double Money;
^
a.cc:1:16: error: changes meaning of ‘Money’ from ‘typedef double Money’ [-fpermissive]
typedef double Money;
那么为什么我们不能在类中重新定义类型名称,而可以在内部作用域中?
So why can not we redefine type names in class, but can we in the inner scope?
我的编译器版本是 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
.
该部分还有一个注释:
My compiler version is g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
.
And there is also a note in that section:
虽然重新定义类型名是错误的,但编译器不需要诊断这个错误.一些编译器会悄悄地接受这样的代码,即使程序出错了.
Although it is an error to redefine a type name, compilers are not required to diagnose this error. Some compilers will quietly accept such code, even though the program is in error.
推荐答案
这不是类型独有的.[basic.class.scope]/2:
This is not unique to types. [basic.class.scope]/2:
在类S
中使用的名称N
应在其上下文以及在 S
的完整范围内重新评估时.不违反此规则需要进行诊断.
A name
N
used in a classS
shall refer to the same declaration in its context and when re-evaluated in the completed scope ofS
. No diagnostic is required for a violation of this rule.
原因是类作用域中的名称查找有点特殊.考虑:
The reason is that name lookup in class scope is a little special. Consider:
using Foo = int;
struct X {
Foo a; // ::Foo, i.e., int
void meow() {
Foo b = a; // X::Foo; error: no conversion from int to char*
}
using Foo = char*;
};
成员函数体中的名称查找考虑所有类成员,无论是在成员函数之前还是之后声明(否则,在类定义中定义的成员函数将无法使用在类中稍后声明的数据成员).结果是您得到两个具有不同含义的 Foo
,即使它们在词法上都在类成员 Foo
的声明之前.这很容易导致非常混乱和脆弱的代码,因此标准禁止它.
Name lookup in member function bodies considers all class members, whether declared before or after the member function (otherwise, a member function defined in a class definition wouldn't be able to use a data member declared later in the class). The result is that you get two Foo
s with different meanings, even though they both lexically precede the class member Foo
's declaration. This can easily lead to extremely confusing and brittle code, and so the standard bans it.
相关文章