请参见以下代码:
<bindings>
<binding protocol="http" bindingInformation="*:8080:Your local Ip"/>
</bindings>
当我运行它时,我得到:
#include <iostream>
#include <chrono>
class Parent
{
public:
Parent() = default;
virtual ~Parent() = default;
Parent(const Parent& pr) : i{pr.i} {std::cout << "Parent copy constructor\n";}
Parent& operator=(const Parent& pr) {std::cout << "Parent copy assignment\n"; this->i = pr.i; return *this;}
Parent(Parent&& pr) : i{std::move(pr.i)} {std::cout << "Parent move constructor\n";}
Parent& operator=(Parent&& pr) {std::cout << "Parent move assignment\n"; this->i = std::move(pr.i); return *this;}
virtual void print_i_j() = 0;
int i = 10;
};
class Child : public Parent
{
public:
Child() = default;
Child(const Child& cr) : Parent{cr}, j{cr.j} {std::cout << "Child copy constructor\n";}
Child& operator=(const Child& cr) {std::cout << "Child copy assignment\n"; this->j = cr.j; return *this;}
Child(Child&& cr) : Parent{std::move(cr)}, j{std::move(cr.j)} {std::cout << "Child move constructor\n";}
Child& operator=(Child&& cr) {std::cout << "Child move assignment\n"; Parent::operator=(std::move(cr)); this->j = std::move(cr.j); return *this;}
void print_i_j() {std::cout << "i = "<< i << " j = " << j << std::endl;}
int j = 100;
};
int main(int argc, const char * argv[])
{
Child c;
c.i = 30;
c.j = 300;
c.print_i_j();
Child c2; // leave c2 with defaults (i=10, j=100)
Parent& p_ref = c2;
p_ref.print_i_j();
c2.j = 150;
p_ref.print_i_j();
p_ref = std::move(c); // (1)
p_ref.print_i_j(); // (2)
return 0;
}
据我所知,如此输出所示,由于将派生类的实例移动到对父类的引用中而导致i = 30 j = 300
i = 10 j = 100
i = 10 j = 150
Parent move assignment
i = 30 j = 150
发生了变化,但i
却没有变化。
(2)中打印的结果是否表示(1)中的移动引起切片?还是其他一些行为(甚至是未定义的行为)开始发生?
答案 0 :(得分:6)
可以std :: move导致切片...
不。 std::move
不会导致切片。
但是,将 assignment 分配给基础对象会导致切片,即仅分配了基础,而对象的其余部分不受影响。复制分配和移动分配时都会发生这种情况。但是,移动分配确实需要额外考虑:不仅分配了左操作数的基(如在复制的情况下),而且还仅移了了右操作数的基。
除非通过赋值运算符是虚拟的,否则是否通过引用分配基数都不会影响切片(不过不要使用虚拟赋值运算符;它们不是一个简单/好的解决方案)。
要么:
无论如何,请确保左操作数的静态类型与分配时所期望的一样。
答案 1 :(得分:5)
是的,发生切片是因为静态地选择了移动分配操作符(在编译时),并且左侧的静态类型是Parent&
,而不是Child
:
Child c;
Child c2;
Parent& p_ref = c2;
p_ref = std::move(c); // (1)
为澄清起见,您没有“进入左值引用”。您进入 object ,但不使用移动整个对象(Child::operator=
)的函数,而是仅移动Parent
部分(Parent::operator=
)的函数。
尤其是,移动语义没有什么特别的。相同的行为将适用于任何成员函数。在这种情况下,右侧运算符的类型无关紧要。
class Parent
{
public:
virtual ~Parent() = default;
void func(); // non-virtual, like move assignment
};
class Child : public Parent
{
public:
void func();
};
// usage:
Child c;
Parent& p_ref = c;
p_ref.func(); // calls Parent::func(), not Child::func()