6
struct T
{
    int a;
};

struct C
{
    T& r;
    C(T& v) : r(v) {}
};

struct E : T
{
    T& r;
    E(T const& v) : r(*this), T(v) {}   // ok
};

struct F : C, T // base order doesn't matter here
{
    //F(T const& v) : C(*this), T(v) {}   // error : C::r is not initialized properly
    F(T const& v) : C(*static_cast<T*>(this)), T(v) {}   // ok
    //F(T const& v) : C(static_cast<T&>(*this)), T(v) {}   // ok
};

int main()
{
    T v;
    F f(v);
    f.r.a = 1;
}

虽然在初始化列表中使用这个指针可能会出现问题,但我从没想到这会发生在 POD 上,并且可以通过显式转换简单地修复;这是一些编译器错误或标准相关问题吗?

4

4 回答 4

3

当您尝试初始化 with 的基CF*this,编译器生成的复制构造函数C和您定义的构造函数T&都是匹配的,因为*this( F) 的类型直接从两者派生C而来T。你的演员解决了这种歧义。

令我惊讶的是,复制构造函数比采用的构造函数更好,T&因为我认为它们都会受到同等的青睐。如果选择了复制构造函数,则基础将从自身初始化,这会导致未定义的行为,因为引用成员将从未初始化的引用(本身)初始化。

于 2012-08-07T14:32:17.180 回答
3

代码模棱两可。

对于构造 的CF,上下文是直接初始化,因此适用 13.3.1.3:

13.3.1.3 构造函数初始化[over.match.ctor]

对于直接初始化,候选函数是被初始化对象的类的所有构造函数。

根据 12.8:8,包含隐式声明的复制构造函数。

的构造函数的候选者CC(T &)和(默认复制构造函数)C(const C &),按参数列表(F)。在这两种情况下,我们都有一个参考绑定 (13.3.3.1.4),然后是一个派生到基础的转换 (13.3.3.1),在后一种情况下还有一个额外的 cv 限定调整,在这两种情况下都给出了转换的总体排名.

由于CT都是 的基类F,但都是不同的类型,并且两者都不是另一个的基类,因此 13.3.3.2:3 和 13.3.3.2:4 中的子句均不适用,并且转换序列无法区分。

事实上,gcc-4.5.1 拒绝代码:

prog.cpp: In constructor 'F::F(const T&)':
prog.cpp:20:34: error: call of overloaded 'C(F&)' is ambiguous
prog.cpp:9:5: note: candidates are: C::C(T&)
prog.cpp:7:1: note:                 C::C(const C&)
于 2012-08-07T15:04:40.620 回答
0

1)切勿在初始化列表中使用 this http://msdn.microsoft.com/en-us/library/3c594ae3(v=vs.80).aspx this 指针仅在非静态成员函数中有效。它不能在基类的初始化列表中使用。

在此构造函数之前调用基类构造函数和类成员构造函数。实际上,您已将指向未构造对象的指针传递给另一个构造函数。如果那些其他构造函数访问任何成员或在 this 上调用成员函数,则结果将是未定义的。在所有构造完成之前,您不应使用 this 指针。

很快:Cr 由坏指针初始化

于 2012-08-07T14:55:01.993 回答
0
结构 C
{
    T&r;
    C(T&v) : r(v) {}
};

结构 E:T
{
    T&r;
    E(T const& v) : r(*this), T(v) {} // 好的
};

您需要在声明时初始化任何引用,但在这里您刚刚声明了它。这在 C++ 中是不允许的。

于 2012-08-07T14:34:32.470 回答