转换为基础引用和复制是一个肮脏的黑客,但究竟什么是脏的呢?

Sev*_*yev 2 c++ coding-style

问题:我有一个非常大的POD变量结构,我需要复制一些字段,而不是其他字段.太懒了写下逐个成员的复制功能.

解决方案:将可复制字段移动到基础,分配基础.像这样:

struct A
{
   int a, b, c;
};

struct B : public A
{
    int d, e, f;
};

//And copy:

B x, y;
(A&)x = y; //copies the part of B that is A
Run Code Online (Sandbox Code Playgroud)

现在,这很脏,我知道.我与同事们进行了一场生动,激烈的讨论:这段代码,我的能力和道德品质.然而,我听到的最难的具体指控是"d,e,f没有在副本中初始化".是的我知道; 这是意图.当然我在其他地方初始化它们.

另一项指控是"不安全的类型转换".但这是对基类的保证安全的类型转换!几乎就是这样

((A*)&x)->operator=(b);
Run Code Online (Sandbox Code Playgroud)

但不那么冗长.推导是公开的; 因此将B视为A是公平的游戏.据我所知,没有未定义的行为.

所以,我呼吁SO的集体智慧.这是批评的邀请.人们,去吧.

编辑:片段的最后一行可以通过多种方式扩展为不那么令人反感的代码.例如:

void Copy(A& to, const A& from)
{
    to = from;
}

B x, y;
Copy(x, y);
Run Code Online (Sandbox Code Playgroud)

功能相同.或者像这样:

x.A::operator=(y);
Run Code Online (Sandbox Code Playgroud)

编辑2:除了我,没有维护程序员.这是一个爱好项目.所以不要怜悯那个可怜的灵魂.

AnT*_*AnT 6

这一切都取决于背景以及在哪个部分被认为是"脏"的.

首先,"切片复制"技巧在技术上是合法的.在形式上,它并不是真正的"黑客".您还可以通过使用赋值运算符的限定名称来引用运算符来获得相同的结果A

x.A::operator =(y); // same as `(A&) x = y` in your case
Run Code Online (Sandbox Code Playgroud)

它开始看起来很熟悉,不是吗?是的,如果你必须在派生类中实现赋值运算符,如果你突然决定手动执行它,那就是你要做的

B& B::operator =(const B& rhs) 
{
  A::operator =(rhs); // or `this->A::operator =(rhs)`

  // B-specific part goes here
}
Run Code Online (Sandbox Code Playgroud)

A::operator =(rhs);部分与上面的"切片复制"技巧完全相同,但在这种情况下,它在不同的上下文中使用.当然,没有人会因为后者的使用而责怪你,因为这是通常的做法以及应该如何做.因此,诀窍的具体应用的"肮脏"取决于上下文.它作为派生赋值运算符的实现的一个组成部分是完全正确的,但是在你的情况下"单独使用"它可能看起来非常值得怀疑.

然而,其次,更重要的是,在你的情况下我称之为"脏"的不是使用"切片复制"本身的技巧.从你在你的问题中描述的东西,它看起来像你实际上分割你的数据结构分为两大类(AB)为能够使用上述伎俩的目的.就是我在这种情况下称之为"脏"的东西.不是"切片复制"技巧本身,而是使用继承仅用于启用"切片复制".如果你这样做只是为了避免手动编写赋值操作符,那就是公然懒惰的一个例子.那就是这里的"脏".我不会'