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