C++ 转换操作符正在切片我的对象

C++ 转换操作符正在切片我的对象,c++,object-slicing,conversion-operator,C++,Object Slicing,Conversion Operator,我从以下代码中获得意外行为: struct Base { Base() {} virtual ~Base() {} virtual void foo() const = 0; protected: Base(const Base &) {} }; struct Derived : public Base { Derived() {} Derived(const Derived &other) : Base(other) {}

我从以下代码中获得意外行为:

struct Base
{
    Base() {}
    virtual ~Base() {}

    virtual void foo() const = 0;

protected:
    Base(const Base &) {}
};

struct Derived : public Base
{
    Derived() {}
    Derived(const Derived &other) : Base(other) {}

    virtual void foo() const {}
};

struct NewDerived
{
    operator const Derived() { return Derived(); }
};

void func(const Base &b)
{
    b.foo();
}

int main()
{
    func(NewDerived());
    return 0;
}
在MSVC2008中,我在main()中遇到以下编译错误:

为什么它试图访问Base的复制构造函数

如果我将Base的复制构造函数设置为公共的,那么代码会在运行时编译并分割返回值,并且在func()中调用foo()会触发一个名为error的纯虚拟函数


有人能解释一下吗?

标准中的相关引用在8.5.3p5(C++11)中:

具有类类型(即T2是类类型),其中T1不是 与T2相关的引用,并且可以隐式转换为xvalue, prvalue类,或“cv3 T3”类型的函数左值,其中“cv1 T1”为 与“cv3 T3”兼容的引用,则该引用绑定到 初始值设定项表达式的值(在第一种情况下)和 第二种情况下的转换结果(或在任何一种情况下,转换为 适当的基类子对象

例如:

在您的情况下,
T1
Base
T2
NewDerived
T3
Derived
。从上面的引用中,不应调用复制构造函数,并且左值引用应绑定到
Base
子对象

但是,请注意,在C++03中,情况并非如此。在C++03中,以下引用是相关的:

如果初始值设定项表达式为右值,T2为类类型,并且 “cv1 T1”是与“cv2 T2”兼容的引用,引用是绑定的 到由右值表示的对象(请参见3.10[basic.lval]),或到 该对象中的子对象

否则,将创建并初始化“cv1 T1”类型的临时文件 使用非引用的规则从初始值设定项表达式 复制初始化(8.5[dcl.init])。然后将引用绑定到 临时的


引用的第一段不适用,因为
Base
NewDerived
的引用不兼容,因此只有最后一段适用,这意味着必须创建临时
Base
对象。因此,MSVC2008和gcc符合C++03规则。

作为旁注,为什么对代码的以下细微更改允许它进行编译,至少在VS中是这样:
int main(){const Base&b(NewDerived();}
有什么想法吗???@AlexK:你被打动了。尝试
const Base&b((NewDerived())(注意额外的括号)。@Jesse明白了。太棒了!谢谢大家。那很有帮助。如果你有任何创造性的想法,我会加上一个额外的问题。@kede:很难用一小段代码就说出来。我不明白为什么转换函数不返回
文件
?也许单独问一个完整代码的问题会有所帮助。
error C2248: 'Base::Base' : cannot access protected member declared in class 'Base'
struct A { };
struct B : A { } b;
extern B f();
const A& rca2 = f(); // bound to the A subobject of the B rvalue.
A&& rra = f(); // same as above
struct X {
operator B();
operator int&();
} x;
const A& r = x; // bound to the A subobject of the result of the conversion