这是一个在没有警告的情况下编译的程序。 GNU C ++:
$ g++ -o t -Wall -pedantic -Wshadow t.cpp
$ ./t.exe
Calling barney::barney()
Calling foo::operator()()
Calling barney::barney()
但它完全无法在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
更重要的是,当它编译时,输出不是我所期望的。有人可以阐明这段代码所需的标准行为吗?
这是:
#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;
}
输出:
Calling barney::barney()
Calling foo::operator()()
Calling barney::barney()
但我希望如此:
Calling barney::barney()
Calling barney::barney()
为什么我得到输出?这是标准行为吗?如果是,为什么,标准的哪些部分是相关的?
除了接受的答案外,David Rodriguez还提供了excellent answer detailing where it says in the standard that I'm allowed to declare the member named fred
of struct fred
。
答案 0 :(得分:6)
因为在fred
结构中,您有一个成员fred
(类型为foo
),它会影响struct fred
的定义。然后当你这样做:
return fred();
... fred
引用foo
类型的对象而不是fred
结构类型,因此调用foo
()运算符。
请注意,名称“fred”指的是两个不同的东西 - 成员,类型为foo,以及fred
结构类型。编译器必须选择其中一个,并且它是根据C ++标准的第3.4节(“名称查找”)中定义的规则执行的。
您可以强制fred
使用命名空间限定来引用类型:
return ::fred();
答案 1 :(得分:6)
在上应该生成错误部分问题。不符合标准:
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;
使用这两个定义,test
引用函数(或变量),struct test
引用用户定义的类型。这是特殊的极端情况,在C语句中声明typedef
时使用struct
会在C ++中产生差异,因为它会在公共标识符空间中注入名称:
typedef struct test {} test; // now "test" is in both spaces
// void test() {} // error: redefinition of "test"
答案 2 :(得分:3)
当您致电f.memfunc
时,对fred()
的调用将解析为fred
类型的foo
成员。将memfunc
声明为返回struct fred
对你没有任何帮助,因为你不能对C ++中的返回值进行多态化。
要使fred()
调用解析为struct fred
的构造函数,请使用命名空间(::fred()
)限定调用。
答案 3 :(得分:1)
正如其他人所指出的那样,您正在呼叫成员operator()
上的fred
。更改成员的名称,或使用::fred()
引用全局范围中的结构fred
。