2010-02-03 34 views
2

我有以下的C++代码在Visual Studio 2005 ...C++:当类构造函数有一个多态参数时,为什么VS2005将本地实例的直接初始化解释为函数?

class Base {}; 
class Derived : public Base {}; 

class Other { 
public: 
Other(const Base& obj) {} 
void test() {} 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
Other other(Derived()); 
other.test(); 
return 0; 
} 

...编译失败,并给出:

test.cpp(19) : error C2228: left of '.test' must have class/struct/union 

我已经通过了一些测试来确定,出现这种情况是因为“其他”变量的声明被解释为一个函数声明(返回一个Other并采用Derived参数),而不是使用单参数构造函数的Other实例。 (VS6发现构造并进行编译罚款,但它并不擅长的C++标准,所以我不相信它比VS2005)

如果我做...

Other other(static_cast<Base&>(Derived())); 

...或者使用复制初始化,它工作正常。但似乎并没有看到Derived()实例是从Base派生的,或者它优先考虑函数声明,而不是尝试构造函数参数的多态性。

我的问题是:这是标准的C++行为,还是这个VS2005的特定行为?应该...

Other other(Derived()); 

...在标准C++中声明一个本地实例,还是应该声明一个函数?

+0

FYI,这个问题被称为“最让人头疼的解析” – 2010-02-04 00:35:24

+0

你错过了'Other'类的一些分号,但这不是你问题的一部分... – 2010-02-04 03:21:03

回答

3

是的,这是标准行为。见this C++ FAQ-lite entry

根据标准,这一点:

Other other(Derived()); 

被解释为函数声明,返回其他和作为一个参数,返回导出并没有参数另一个函数的函数。为了解决这个问题,你可以使用:

Other other = Other(Derived()); 
+0

哇,谢谢。具有讽刺意味的是,我已经阅读过这个链接,但一定已经忘记了(可能是因为背后的原因 - 参数解释 - 相当隐晦)。我认为它与多态性有关,因为static_cast (...)也起作用。 – DustOff 2010-02-04 00:28:16

1

我想你的例子在VS2008和GCC和它发生也有。

它看起来像什么,是这句法实际上是宣告另一个作为一个函数指针与此声明:

Other other(Derived (*)(void)) 

正确的行为应该是使用初始化:

Other other = Derived(); 
2

您提你的问题标题中的“多态参数”,而事实上,所有这些与多态参数完全无关。在C++中,有问题的声明会声明一个函数,而不管您提供的“参数”是否是多态的。

像往常一样,你可以使用一个额外的对()来解决此问题

Other other((Derived())); // now it is an object, not a function 

你也可以用任何其他方法,以打开Derived()部分到表达,像

Other other((const Derived&) Derived()); 

Other other(((void) 0, Derived())); 
+0

谢谢,是的,我意识到第一个答案后,多态性的事情来自我自己的假设由于环境(我不认为尝试static_cast (...),这将使这显而易见)。额外的括号将非常有帮助。但是,有点题外话,((void)0,Derived())做什么? – DustOff 2010-02-04 00:43:37

+0

@DustOff:'((void)0,Derived())'是一个在中间包含逗号运算符的表达式。逗号运算符的结果是它的最后一个子表达式 - “Derived()” - 这就是我们所需要的。第一个子表达式 - ((void)0) - 被忽略。只是一个简单的'0'(或'1'或'42')也会起作用,但是编译器会发出关于“无效”表达式的警告。投向'(void)'会抑制警告。这种奇怪的方法的价值当然是纯学术的 – AnT 2010-02-04 01:24:13

相关问题