1

是否有任何 C++ 对象切片效果的示例可能导致未定义的行为、内存泄漏或在其他正确的代码集中崩溃?例如,当 classAB(继承自A)是正确且合理的,但调用 avoid f(A a)显然会导致讨厌的事情。

它是形成测试问题所必需的。目标是使用示例代码片段了解参与者是否意识到切片现象,该示例代码片段的正确性绝不能是意见问题。

4

3 回答 3

4

如果A确实“正确且合理”,那么切片(复制基本子对象)是明确定义的,不会导致您提到的任何问题。如果您希望副本的行为类似于B.

如果A不能正确复制,那么切片将导致复制该类型对象时出现的任何问题。例如,如果它有一个析构函数删除对象持有的指针,并且复制创建一个指向同一事物的新指针,那么当两个析构函数删除同一个指针时,您将获得未定义的行为。这不是切片本身的问题,而是切片对象的无效复制语义。

于 2012-11-28T13:35:19.453 回答
1

你总是可以构建这样一个例子

struct A {
  A() : invariant(true) {}
  virtual void do_sth() { assert(invariant); }
protected:
  bool invariant;
};

struct B : A {
  B() { invariant=false; }
  virtual void do_sth() { }
};

void f(A a)
{
  a.do_sth();
}

当然A,当复制构造函数/赋值运算符不检查不变量是否为真时,这可以在内部防止。

如果不变量比我的布尔值更隐含,那么这些东西可能很难看。

于 2012-11-28T13:33:33.933 回答
1

只有当您通过指针或对其基类的引用来操作派生类时,对象切片才是真正的问题。然后,派生类的附加数据保持不变,而基础部分的数据可能会被改变。这可能会破坏派生类的不变量。一个简单的例子见http://en.wikipedia.org/wiki/Object_slicing

但是,我认为这是(派生类的)设计缺陷。如果通过任何合法的方法访问一个类,包括那些获取基类的指针或引用参数的方法,都可能破坏它的不变量,那么这个类的设计很糟糕。避免这种情况的一种方法是声明基private类,这样派生类就不能通过其基类合法访问。

一个例子是:

class A
{
  int X;
  A(int x) : X(x) {}
  void doubleX() { X+=X; }
  /* ... */
};

class B : public A
{
  int X_square;
  B(int x) : A(x), X_square(x*x) {}
  /* ... */      
};

B b(3);
B.doubleX();   /// B.X = 6 but B.X_square=9

从这个例子中也很明显,这是 B 中的一个简单的设计缺陷。在这个例子中,提供

void B::doubleX() { A::doubleX(); X_squared=X*X; }

不能解决问题,因为

A&a=b;
a.doubleX();

仍然打破不变量。这里唯一的解决方案是声明基A私有,或者更好的是,创建A一个私有成员,而不是基,B

于 2012-11-28T13:46:51.613 回答