根据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
答案 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