一个困惑的类层次设计根据:回调函数,避免向下类型转换(转)

来源:互联网 发布:阿里云 合作伙伴 列表 编辑:程序博客网 时间:2024/05/16 06:20

 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() ;
}

我实在看不出这样拆分后添加虚函数有什么特别的好处,不是跟直接在分类中添加虚函数的做法一样么?
----------------------------------------------------------------------------------
如果程序比较小,用处不大,如果系统比较大,拆分后模块的结构会清晰些
对于原来的部分,咱认为是系统中以后不用改变的,归在同一个类里面。可变的部分,你在子类中新添加的东西,可统一归到另外一个类中。说白了,就是以后出问题,我可以很快的撇清关系,如果俺负责那原来不变的类的开发的话
原创粉丝点击