一般来说,这些都应该是复制操作,有时首先是转换。我将在下面介绍移动操作。
第 1 部分:我将要使用的语言可能与标准略有不同,但我倾向于认为rb
是指整个对象d
。我这么说的原因是,当我在做这样的事情时,D
几乎总是至少有一个虚函数,并且任何通过调用的虚函数rb
都会运行从 . 开始的版本D
,而不是B
. 例如,如果我们有:
class B
{
public:
virtual int get_value() { return 10; }
};
class D: public B
{
public:
virtual int get_value() { return 20; }
};
然后rb.get_value()
将返回 20,而不是您可能想的 10。
第 2 部分:这实际上是您几乎不想做的事情。这里发生的情况是,通过称为“切片”的过程d
将 转换为 a B
,该过程丢弃D
唯一的部分并仅留下B
部分,然后将其复制到 create newb
。这听起来很有用,但实际上您可能想要创建一个完整的副本d
而不是部分副本,或者您根本不想创建一个副本而是想要使用指针或引用d
.
如果你想创建一个完整的副本,你可能需要一个虚函数来做这个副本,像这样:
class B
{
public:
virtual B *clone()
{
return new B(*this);
}
};
class D: public B
{
public:
virtual B *clone()
{
return new D(*this);
}
};
第 3 部分:这与第 2 部分基本相同 - static_cast
just 的存在使切片变得明确,而不是编译器自动执行的操作。同样,这可能不是您经常想要做的事情。
根据上下文,您正在使用的表达式可能会变成移动操作。例如,如果d
即将被销毁,编译器可能会识别并调用移动函数而不是副本,因为移动通常更有效。例如:
B foo()
{
D d;
return d;
}
在 C++11 中,返回语句可能会调用移动构造函数(如果存在)而不是复制构造函数来创建返回值。也就是说,效果应该非常相似——在第 2 部分和第 3 部分中发生的切片将发生在调用两个构造函数中的任何一个。