如何确保此树中的可分配性?

时间:2009-07-06 03:01:39

标签: c++

根据CBase(单继承)存在类的树。 CSub来自CBase,以及来自CBase或CSub的其他类, 和CBase具有虚拟成员函数。

所有课程都必须是可分配的。有些类有成员(指针) 在任务中需要特殊处理(指针)。 如何确保此类树中的可分配性?

首先,我认为我需要将“operator =”虚拟化。 然后我意识到这是错的。 那么这就是可能的:

         CBase *x = new CSub; 
         CBase *y = new CSub; 
         *x = *y; // is this okay ?

如果没有,我如何在没有邪恶的垂头丧气的情况下将* y分配给* x?我有很多 问题在这里。

如果我每次通过CBase *分配时都需要进行转换,那么这样做 看起来不安全,不是吗? 我是否需要在“operator =”中插入类型检查以检查lhs和 rhs有相同的类型? 等等。欢迎举例。

由于 VIKI

4 个答案:

答案 0 :(得分:1)

我相信这是一个简单的问题。你需要实现“虚拟赋值运算符”,它需要upcast imho:

class CBase {

...
   virtual assign(const CBase & from) = 0;
...
};

class CSub {
...
   void operator=(const CSub & from) { assign(from); }

   virtual assign(const CBase & from) {
      if (dynamic_cast<const CSub &>(from)) {
         ... implement simple copy here
      } else {
         ... you'll have to decide what to do with other types
      }
   }
};

答案 1 :(得分:0)

为什么他们需要分配?您将无法安全/正确地执行它并仍然允许新的子类,或者您将最终以编译时完全知道所有类型的对象的方式编写代码,并且您可以避免该问题完全。我会建议使用virtual CBase* copy() const方法。它可以在子类中使用协变返回。不需要向下转换,也没有切片的可能性。

答案 2 :(得分:0)

你提出的代码确实表现出“邪恶的倾向”(像疯了一样切断事情) - 如果CBase是一个具有普通和可用的赋值运算符的具体类,它将始终“意外地”工作(并且我再一次重复Haahr的建议:不要子类[如果你有一个vtable或任何额外的数据,即任何“严肃的”子类;-)]来自具体的类,只来自抽象的 - 除了你将从中保存的其他优点意外和误导“干净编译代码”,当它运行时可能会做错误的事情。)

如果你希望树中的每个子类都可以从任何其他实例中分配(如果CBase有一个赋值运算符,那么Liskov的原理应该是这样),你需要从CBase中分配任何子类。确保它处理该路由不知道的任何子类(忽略未知兄弟类可能添加的任何额外数据,叹息) - 或尝试使用例如更可虚拟化的路由一个virtual void assign(const CBase*)方法(不要求CBase是具体的,顺便说一句; - )。

这仍然没有解决可能有N平方特殊情况的问题;为此,您可以尝试访问者或(可能更好)Uncle Bob的Acyclic Visitor(更好的方法是使用命名方法而不是operator=,但是; - )。

答案 3 :(得分:0)

这里你正在处理指针,所以你需要小心:

 CBase *x = new CSub; 
 CBase *y = new CSub; 
 *x = *y; // is this okay ?

上面的代码导致内存泄漏,因为x没有释放它指向的CSub对象。

当您处理指针时,您需要处理他们可能指向的先前内容。

您可以使用auto_ptr或其他智能指针来实现此目的:

std::auto_ptr<CBase> x( new CSub );
std::auto_ptr<CBase> y( new CSub );
x = y;    // x now owns the obj that y pointed to, x's old obj has been deleted

使用boost模板库:

boost::shared_ptr<CBase> x( new CSub );
boost::shared_ptr<CBase> y( new CSub );
x = y; // now x and y point to same obj, old obj x pointed to has been deleted.

好的,这不是你要问的,但我想我会覆盖以防万一。

到问题的作业部分

为了安全起见,您需要为每个类创建operator =()。这是控制赋值的方法,因为你可能有成员指针等。

class CBase // should be made abstract
{
public:
   CBase() { ; }
   CBase& operator=(CBase& in) { copy members }
};

class CSub : public CBase
{
public:
  CSub() {;}
  CSub& operator=(CSub& in ) { copy members from in, and base class members }
};

HTH