这是一个在没有警告的情况下编译的程序,例如GNU C++:
$ g++ -o t -Wall -pedantic -Wshadow t.cpp
$ ./t.exe
Calling barney::barney()
Calling foo::operator()()
Calling barney::barney()
Run Code Online (Sandbox Code Playgroud)
但它完全无法在MSVC++上编译:
$ cl /EHsc t.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
t.cpp
t.cpp(17) : error C2380: type(s) preceding 'fred' (constructor with return type, or illegal redefinition of current class-name?)
t.cpp(17) : error C2208: 'fred' : no members defined using this type
Run Code Online (Sandbox Code Playgroud)
更重要的是,当它编译时,输出不是我所期望的.有人可以了解这段代码所需的标准行为吗?
这里是:
#include <iostream>
using ::std::cerr;
struct fred;
struct foo {
inline fred operator ()();
};
struct barney {
barney() : v_(0) { cerr << "Calling barney::barney()\n"; }
int v_;
};
struct fred : public barney {
foo fred;
int joe;
struct fred memfunc() { return fred(); }
};
inline fred foo::operator ()()
{
cerr << "Calling foo::operator()()\n"; return fred();
}
int main(int argc, const char *argv[])
{
fred f;
f.memfunc();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它输出这个:
Calling barney::barney()
Calling foo::operator()()
Calling barney::barney()
Run Code Online (Sandbox Code Playgroud)
但我希望如此:
Calling barney::barney()
Calling barney::barney()
Run Code Online (Sandbox Code Playgroud)
为什么我得到输出?这是标准行为吗?如果是,为什么,标准的哪些部分是相关的?
除了公认的答案,大卫·罗德里格斯给了一个优秀的答案,详述它在我被允许申报命名该成员的标准说fred的struct fred.
因为在fred结构中你有一个阴影定义的成员fred(类型foo)struct fred.当你这样做:
return fred();
Run Code Online (Sandbox Code Playgroud)
... fred指的是类型的对象foo而不是fred结构类型,因此foo调用()运算符.
请注意,名称"fred"指的是两个不同的东西 - 成员,类型为foo,以及fred结构类型.编译器必须选择其中一个,并且它根据C++标准的3.4节("名称查找")中定义的规则执行此操作.
您可以强制fred使用命名空间限定来引用类型:
return ::fred();
Run Code Online (Sandbox Code Playgroud)
在它上面应该生成一个错误部分的问题.不符合标准:
9.2 [class.mem]/13
如果T是类的名称,则以下每个名称都应具有与T不同的名称:
9.2 [class.mem]/13a
此外,如果类T具有用户声明的构造函数(12.1),则类T的每个非静态数据成员都应具有与T不同的名称.
至于它为什么找到成员而不是变量,这与在C++中如何处理标识符非常一致,其中有两个标识符空间,一个用于用户定义的类型,另一个用于其他元素(包括typedef) ):
struct test {};
void test() {}
// or (but not both)
// int test;
Run Code Online (Sandbox Code Playgroud)
使用这两个定义,test指的是函数(或变量),以及struct test用户定义的类型.这是一个特殊的极端情况,在C语言中typedef声明使用时struct会在C++中产生差异,因为它会在公共标识符空间中注入名称:
typedef struct test {} test; // now "test" is in both spaces
// void test() {} // error: redefinition of "test"
Run Code Online (Sandbox Code Playgroud)