【问题标题】:Why does slicing a non-root base class produce the correct answer?为什么切片非根基类会产生正确答案?
【发布时间】:2013-07-22 05:18:51
【问题描述】:

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

#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

【问题讨论】:

  • 它可能既不安全也不聪明,但它是确定性的:Green 复制构造函数复制您的jerry 对象的Green 子对象,其中q 设置为3
  • 您是否知道标准的一部分解决了这个问题(即保证其确定性?)
  • 不,这不是一种安全的做法,人们通常喜欢避免切片,因为它会带来一些问题。尽管您的程序定义明确(请参阅下面的答案)
  • 将成员变量公开是不安全的做法,它将通过赋值静默(没有错误或警告)被覆盖(通常不是我们所做的)。
  • C++11 4.10/3(指针转换),我想说。

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


【解决方案1】:

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

如果你使用,你会看到相同的结果

const Green& fred = jerry;

在没有执行复制的情况下,您只是访问 jerry 的 jerry 部分,将其命名为 fred

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

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

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

source

【讨论】:

  • 使用这个原理,为什么 Green fred(jerry); 仍然会产生 3?
  • 你知道在 gcc 中生成编译器生成的构造函数的方法吗?
  • 出于同样的原因:Green fred(jerry) 通过调用复制构造函数将 jerry 作为参数传递来构造一个 Green 类型的对象。
  • 我认为没有办法。编译器生成的远不止这些
  • 我也猜想,因为它是一个参考,带有 vtable 的类不会有什么不同?
猜你喜欢
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 2018-04-06
  • 2020-05-31
  • 2022-11-13
  • 2013-10-26
相关资源
最近更新 更多