C++ 为什么切片非根基类会得到正确的答案?
我的代码中有一个例子,我想使用对象切片,但我试图确定这样做是安全的还是明智的。为了确定这一点,我运行了以下示例:C++ 为什么切片非根基类会得到正确的答案?,c++,c++11,multiple-inheritance,object-slicing,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{ publ
#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;
}
正在发生的事情是,fred正在使用编译器合成的复制构造函数构造,该构造函数将
const Green&
作为参数。它执行jerry的绿色部分内容的浅拷贝
如果您使用
const Green& fred = jerry;
如果没有进行复制,您只需访问jerry的jerry部分,将其命名为fred
至于问题的另一部分,你的设计没有什么不安全的地方,只是它很“复杂”,你需要知道发生了什么。您可能需要阅读和相关页面,以便对该主题进行一些讨论
当然,您可以定义具有不同行为的复制构造函数/运算符。或者您可以禁止编译器生成它们
处理这些问题的传统方法是声明私有副本构造函数和副本赋值,然后记录为什么会这样
完成。在C++2011中引入了一个新的替代方案,声明了一个副本
构造函数和复制赋值运算符,但都标记为
删除。从noncopyable派生更简单、更清晰,而且
不需要额外的文档
发生的事情是,fred正在使用编译器合成的复制构造函数构造,该构造函数将
常量Green&
作为参数。它执行jerry的绿色部分内容的浅拷贝
如果您使用
const Green& fred = jerry;
如果没有进行复制,您只需访问jerry的jerry部分,将其命名为fred
至于问题的另一部分,你的设计没有什么不安全的地方,只是它很“复杂”,你需要知道发生了什么。您可能需要阅读和相关页面,以便对该主题进行一些讨论
当然,您可以定义具有不同行为的复制构造函数/运算符。或者您可以禁止编译器生成它们
处理这些问题的传统方法是声明私有副本构造函数和副本赋值,然后记录为什么会这样
完成。在C++2011中引入了一个新的替代方案,声明了一个副本
构造函数和复制赋值运算符,但都标记为
删除。从noncopyable派生更简单、更清晰,而且
不需要额外的文档
它可能既不安全也不智能,但它是确定性的:
Green
copy构造函数复制jerry
对象的Green
子对象,该对象的q
设置为3
。您知道标准中有一节解决了这一问题(即保证其确定性吗?)否,这不是一种安全的做法,人们通常喜欢避免切片,因为切片会带来问题。虽然您的程序定义得很好(请参见下面的答案),但将成员变量保留为public并不是一种安全的做法,它将使用赋值(C++11 4.10/3(指针转换))以静默方式重写(通常不是我们所希望的)它可能既不安全也不智能,但是它是确定性的:Green
copy构造函数复制您的jerry
对象的Green
子对象,该对象的q
设置为3
。您知道标准中有一部分解决了这一问题(即保证其确定性吗?)。不,这不是一种安全的做法,人们通常喜欢避免切片,因为切片会带来问题。虽然你的程序定义得很好(见下面的答案),但将成员变量保留为public并不是一种安全的做法,它将被赋值悄悄地覆盖(通常不是我们所希望的)(没有错误或警告)。我想说,C++11 4.10/3(指针转换);结果仍然是3?你知道在gcc中生成编译器生成的构造函数的方法吗?出于同样的原因:Green fred(jerry)通过调用复制构造函数(将jerry作为参数传递)来构造一个Green类型的对象。我认为没有办法。编译器生成的远远不止这些,我还猜测,因为它是一个引用,所以带有vtable的类不会有什么不同;结果仍然是3?你知道在gcc中生成编译器生成的构造函数的方法吗?出于同样的原因:Green fred(jerry)通过调用复制构造函数(将jerry作为参数传递)来构造一个Green类型的对象。我认为没有办法。编译器生成的远远不止这些,我还猜测,因为它是一个引用,所以带有vtable的类不会有什么不同?