class Element
{
virtual void doSomething();
};
ElementTree
{
Element * getElementInTree() {return data[i];}
void setElementInTree(Element* e) { e->doSomething(); i++; data[i]=e;}
private:
Element * data[] ;
int i;
};
class RedElement:Element
{
void doSomething() {int a=0; a++; ... ... };
void redDoSomething();
}
main()
{
Element *e = new RedElement();
ElementTree tree;
tree.setElementInTree(e);
Element *eBack = tree.getElementInTree();
//以下为了调用RedElement中才有的方法,不得不向下转化
RedElement *redEBack = dynamic_cast<RedElement>(eBack);
redEBack.redDoSomething() ;
}
关于上面的例子的问题:
effective c++中39条讲最好不要沿着类继承关系向下转换,那么是不是向下转换应该尽量少用?在什么情况下可以使用?
以上的的例子怎样重新设计,避免向下转换?
讲出这样设计的根据是什么,是什么设计理念使你这样做?
一般都不能使用,用了说明你的设计不好,基类没有很好的抽象。
只能在基类新增一个方法。
楼主,切忌,莫将一个 基类对象 指针 转换为一个 派生类 对象指针,除非你有十足的把握
的确不应该把基类指针转换成为派生类指针。
但是谁能说说上面的代码为什么没道理。应该怎样做才对,为什么要这样做。
比如:
说基类应该多定义虚函数的,有什么设计准则可依据,子类中不能另外添加新的方法?
说上面编码没有道理的,那么应该依据什么设计准则,如何重构一下得到正确的编码从而避免向下转换?
我来总结一下问题吧:
情况一:如果redDoSomething是基类的行为,那么在基类添加虚函数的方式肯定是可以避免向下转换的.
但是实际上的问题是,开发基类的人是一个组,使用基类来开发派生类的人是另外一组.开发基类的时候并不知道子类可能有那么多别的需求.
这样的情况我的认为是也许我们需要重新将两个组沟通,来重新设计基类.也许需要重构整个代码.
这样做也会造成很大的消耗,必须重复经历一个开发周期.我不知道这个是不是采用C++才会有的问题,还是无论什么语言来开发都会有的问题(整个软件开发必须处理的问题),还是说有什么更好的方法来解决?
情况二:如果redDoSomething不是基类的行为.那么这样在派生类中添加基类中没有的方法,这样的做法是否有问题.(但是据我所看到的,这样做好像很普遍.)
如果有问题的话,那么我觉得实际开发中几乎不可能.而且这样的话开发基类的人几乎得是神才可能做到(因为他必须预先知道所有子类的所有方法并把他们写成虚函数)
如果没有问题的话,那么这样的向下转换在很多情况下将难以避免...
虚函数,只是在不同子类对应的行为可能不同时,才使用。这时RTTI(Run-Time Type Identification,通过运行时类型识别)的准则啊。面向对象最关键的一点是多态,也就是虚函数了,至于虚函数的原理,可以先理解下虚函数表。
楼主的想法,应该是符合开放封闭原则,对修改封闭,对扩张开放。开放的放在public下,封闭的放在private下,当然对于基类的抽象要尽量抽象,不依赖于具体,而且功能要单一,符合单一职责的原则。这样设计会好些吧。希望能对你有帮助
可以把类拆为可变的不变的吧
然后可变的类随便添加虚函数,不变的部分保持。 class Element { public: virtual void doSomething(); CAlter *m_pAlter; }; clasa CAlter { public: virtual void redDoSomething(); } class CRedAlter:public CAlter { public: void redDoSomething(){.....}; } ElementTree { Element * getElementInTree() {return data[i];} void setElementInTree(Element* e) { e->doSomething(); i++; data[i]=e;} private: Element * data[] ; int i; }; class RedElement:Element { void doSomething() {int a=0; a++; ... ... }; void redDoSomething(); } main() { Element *e = new RedElement(); ElementTree tree; CAlter *a= new CRedAlter; e->m_pAlter=a; tree.setElementInTree(e); Element *eBack = tree.getElementInTree(); //以下为了调用RedElement中才有的方法,不得不向下转化 //RedElement *redEBack = dynamic_cast<RedElement>(eBack); eBack->m_pAlter->redDoSomething(); //redEBack.redDoSomething() ; } |