为什么切片非根类会产生正确的答案?

时间:2013-07-23 08:28:23

标签: c++ c++11 multiple-inheritance object-slicing

我的代码中有一个案例,我想使用对象切片,但我正在尝试确定它是否安全或聪明。在尝试确定这一点时,我运行了以下示例:

#include <iostream>

using namespace std;


class Dog{

    public:
        Dog( int x )
            :x{x}
        {

        };

        int x;

};


class Spaniel: public Dog{

    public:
        Spaniel( int x, int y )
            :Dog{x}, y{y}
        {

        }

        int y;

};


class Green{

    public:
     Green( int q )
         :q{q}
     {

     }

     int q;

};


class GreenSpaniel: public Spaniel, public Green{

   public:
        GreenSpaniel( int x, int y, int q, int z )
            :Spaniel{x,y}, Green{q}, z{z}
        {

        }

        int z;

};



int main(){

    GreenSpaniel jerry{ 1,2,3,4 };

    Green fred = jerry;

    cout << fred.q << endl;  //correctly displays "3"

    return 0;

}

我希望它返回1,因为基类不是最顶层的(根),但它显示3.所以,我的问题是为什么/如何显示正确的答案,这是一个安全的做法?如果任何类有虚拟表,你的答案会如何改变?如果您认为不安全,那么从派生对象复制非根基础对象是否有任何变通方法?

我使用以下命令在gcc 4.6.3下在linux中运行它:

g++ -std=c++0x main.cc

1 个答案:

答案 0 :(得分:4)

正在发生的是fred正在使用编译器合成的复制构造函数构造,该构造函数将const Green&作为参数。它执行jerry绿色部分内容的浅层副本。

如果使用

,你会看到相同的结果
const Green& fred = jerry;

在没有执行任何副本的情况下,您只需访问jerry的jerry部分,名称为fred

至于问题的其他部分,你的设计没有什么不安全的,只是它“复杂”,你需要知道发生了什么。您可能需要阅读this和相关页面,以便对该主题进行一些讨论。

当然,您可以定义自己的具有不同行为的复制构造函数/运算符。或者你可以禁止编译器生成它们

  

处理这些问题的传统方法是声明私有拷贝构造函数和拷贝分配,然后记录这是为什么   完成。 C ++ 2011中引入了一种新的替代方案,声明了一个副本   构造函数和复制赋值运算符,但都标记为   删除。从noncopyable派生更简单,更清晰,并且   不需要额外的文档。

source