我的代码中有一个案例,我想使用对象切片,但是我试图确定这样做是安全还是明智的。为了确定这一点,我运行了以下示例:

#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。所以,我的问题是为什么/如何显示正确的答案,这是安全的做法吗?如果任何类都有虚拟表,您的答案将如何变化?如果您认为它不安全,那么您是否有任何变通办法来从派生对象复制非根基础对象?

我在Linux上的gcc 4.6.3下使用以下命令运行了该命令:

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

最佳答案

发生的情况是,fred是使用编译器综合的副本构造函数构造的,该构造函数将const Green&作为参数。它执行jerry的Green部分内容的浅表副本。

如果您使用过,将会看到相同的结果

const Green& fred = jerry;


如果未执行任何复制,则通过将其命名为fred来访问jerry的jerry部分。

至于问题的另一部分,您的设计没有什么不安全的,只是它是“复杂的”,您需要了解正在发生的事情。您可能需要阅读this和相关页面,以进行有关该主题的讨论。

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


  处理这些问题的传统方法是声明一个私有副本构造函数和副本分配,然后记录为什么这样做
  完成。 C ++ 2011中引入了一个新的替代方法,声明了一个副本
  构造函数和副本赋值运算符,但都将其标记为
  已删除。源自不可复制的过程更加简单明了,并且
  不需要其他文档。


source

关于c++ - 为什么切片非根基类会产生正确的答案?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17805083/

10-15 17:56