Gotw 80包含以下示例:
// Example 1
//
#include <string>
using namespace std;
class A
{
public:
A( const string& s ) { /* ... */ }
string f() { return "hello, world"; }
};
class B : public A
{
public:
B() : A( s = f() ) {}
private:
string s;
};
int main()
{
B b;
}
文章继续讨论为什么s = f()
行是不正确的——由于对象生命周期和构造顺序。文章指出,当时编译器没有发现错误。
然而,忽略初始化顺序和对象生命周期的问题,我看不出构造函数参数列表中的s = f()
在语法上是如何合法的——它似乎试图初始化参数列表中的成员(或者可能声明默认值)。有人能解释一下这个语法是怎么回事吗?
看起来意图是调用f()
并将结果分配给B::s
。之后,该赋值的结果(即s
)将在调用继承的A
构造函数时用作实际参数。
在语法上是有效的。将表达式中的s
替换为某个非成员变量,g++将毫无问题地接受它。您可能会看到类似的语法更多地用于普通函数调用而不是构造函数调用。
语法上是合法的…当你的基类有一个带参数的构造函数时,你当然可以传递任何表达式作为形参:
strut A {
A(int) {}
};
struct B : A {
B() : A( any expression that returns an int ) {}
};
问题是,当计算示例中的表达式时,对象甚至还不是一个完全构造的A
实例,因此由于两个不同的原因,代码无效:
- 调用非实例的
A
方法(构造函数尚未启动):f()
调用是非法的。 - 分配给未初始化的成员:
s=...
是非法的