我正在研究对象切片何时/为何是危险的。
我读到了一个关于 what is safe slicing VS dangerous slicing 的精彩链接.
以下是我可以总结的内容(粗略地说):-
- 安全,当基本类型为值时(例如
A
)。 - 危险,当基本类型为引用时(例如
A&
)。
读完后,我在 Visual Studio + Resharper(VS 插件)中创建了一个测试代码。
我认为我的情况是安全。但是,我在标记行 #1
处收到警告。
possibly unintended object slicing value-initialized from derived class C
class B1{ int field1=0; };
class B2{ int field2=0; };
class C: public B1,public B2{ };
class Test{
void f(B1 b){ } #2
void f2(){
C c;
f(c);
//^ possibly unintended object slicing #1
}
};
Resharper的行为方式与我的信念相矛盾。
- 当类型为值时警告。
- 当类型为引用时无警告(将 #2 从
B1
更改为B1&
)。< - 当
C
仅从B1
派生时,无论#2
是什么,始终无警告。 (B
或B&
)
它可以总结成一个表格:-
| #2=B1 | #2=B1&
==================================================
multi-inherit | warn* | no-warn*
--------------------------------------------------
inherit only from B1 | no-warn | no-warn
但是,这是我所期望的:-
| #2=B1 | #2=B1&
===================================================================
multi-inherit | safe* | dangerous*
-------------------------------------------------------------------
inherit only from B1 | safe | safe
不一致用*
标记。
我是否误解了对象切片,或者Resharper错了?
最佳答案
Resharper acts in a contradict way from my belief.
它以正确的方式运行,让我们看看:
Warning when the type is value.
这是这个代码:
class B1{ int field1=0; };
class B2{ int field2=0; };
class C: public B1,public B2{ };
class Test{
void f(B1 b){ }
void f2(){
C c;
f(c);
}
};
在函数调用中,从 C
类型的变量 c
初始化 B1
类型的变量 b
的值派生自B1
,会执行B1
的一个拷贝构造函数,其签名为B1(const B1& rhs);
,在这个构造函数中(无论是它是否自动生成)只有 B1
中存在的字段将从 rhs
复制,因此其余部分(来自 B2
或 C
) 将被切片。
No warning when the type is reference (change #2 from B1 to B1&).
void f(B1& b){ }
这是正确的,这就是通过将对象分配给基类类型的指针或引用来传递多态对象的方式。
Always no warning when C derived from only B1, no matter #2 is. (B or B&)
那只是因为C
没有字段,所以在这种情况下没有切片。尝试将 int n;
添加到 C
中,警告将再次显示。
关于c++ - 对象切片: pass Derived as Base by value - safe or dangerous?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42649052/