【发布时间】:2012-08-07 00:39:25
【问题描述】:
我希望有一个层次结构的类结构,其中一个级别的控制器“父”类负责创建/指导许多“子”类。父类应该能够直接引用它创建的每个子类,并且每个子类应该能够直接引用它的父类(并且,假设这个子类不是更多类的父类,只是它的父类)。这允许通过父级引用兄弟姐妹。我发现这种范例在 Java 和 C# 等 JIT 编译语言中很有用,但 C++ 存在一个独特的问题......
我第一次尝试实现这个范例如下:
父类 TreeRoot.h
#ifndef __CCPP_SCENE_H__
#define __CCPP_SCENE_H__
#include "ChildA.h"
#include "ChildB.h"
class TreeRoot :
{
private:
ChildA* a;
ChildB* b;
public:
//member getters
ChildA* getA();
ChildB* getB();
};
#endif // __CCPP_SCENE_H__
子类 ChildA.h
#ifndef CHILDA_H_
#define CHILDA_H_
#include "TreeRoot.h"
class ChildA
{
private:
TreeRoot* rootScene;
public:
ChildA(TreeRoot*);
~ChildA(void);
TreeRoot* getRootScene();
void setRootScene(TreeRoot*);
};
#endif /*CHILDA_H_*/
子类 ChildB.h
#ifndef CHILDB_H_
#define CHILDB_H_
#include "TreeRoot.h"
class ChildB
{
private:
TreeRoot* rootScene;
public:
ChildB(TreeRoot*);
~ChildB(void);
TreeRoot* getRootScene();
void setRootScene(TreeRoot*);
};
#endif /*CHILDB_H_*/
当然,由于循环包含(TreeRoot.h 包括 ChildA.h 和 ChildB.h,它们都包括 TreeRoot.h 等),所以现在当然不会编译,所以我尝试使用前向声明:
父类 TreeRoot.h
#ifndef __CCPP_SCENE_H__
#define __CCPP_SCENE_H__
#include "ChildA.h"
#include "ChildB.h"
class TreeRoot :
{
private:
ChildA* a;
ChildB* b;
public:
//member getters
ChildA* getA();
ChildB* getB();
};
#endif // __CCPP_SCENE_H__
子类 ChildA.h
#ifndef CHILDA_H_
#define CHILDA_H_
//#include "TreeRoot.h" //can't use; circular include!
class TreeRoot;
class ChildA
{
private:
TreeRoot* rootScene;
public:
ChildA(TreeRoot*);
~ChildA(void);
TreeRoot* getRootScene();
void setRootScene(TreeRoot*);
};
#endif /*CHILDA_H_*/
子类 ChildB.h
#ifndef CHILDB_H_
#define CHILDB_H_
//#include "TreeRoot.h" //can't use; circular include!
class TreeRoot;
class ChildB
{
private:
TreeRoot* rootScene;
public:
ChildB(TreeRoot*);
~ChildB(void);
TreeRoot* getRootScene();
void setRootScene(TreeRoot*);
};
#endif /*CHILDB_H_*/
该实现几乎可以工作,因为我可以成功地将消息广播到子对象并执行从子对象到父类的回调,如下所示:
TreeRoot.cpp
...
a->someChildMethod();
a->getRootScene()->someParentMethod();
但是当我尝试以下操作时:
ChildA.cpp
...
rootScene->someParentMethod(); //ERROR C2027: use of undefined type TreeRoot
我得到一个未定义的类型错误。这是有道理的,因为使用上面的前向声明并不会告知编译器 TreeRoot 的实际含义。那么问题是如何启用来自子对象的调用,例如上面的 rootScene->someParentMethod() 调用?也许通过模板使用泛型类型会使编译器满意并提供我正在寻找的功能?
谢谢, CCJ
【问题讨论】:
-
恕我直言,但这种“范式”不是推荐的方法。您正在依赖图中创建循环,这是不可以的。您的子对象现在不需要关于父对象。如果需要回调,我建议添加一个独立于父子的接口,由父亲实现,然后由孩子使用。
-
@Alex:正如双向链表有其用途一样,子节点知道其父节点的树也是如此。
-
@Alex 你会建议什么替代设计范式来提供等效的功能(例如,假设子节点确实需要知道它们的父节点)?您将如何实现您建议的接口?
-
这可能是一个很好的例外情况,但是: 1) 分层/非循环设计有一个明确的构造/破坏顺序,这避免了可怕的空指针错误。 2)在我看来,最糟糕的问题是控制问题。在层次结构中,当您构建类时,您依赖于您拥有设计控制权的类,即在层次结构或抽象中位于您之下的类。如果您破坏了这一点并依赖于上层类,那么这些类中的更改将破坏您的代码。见:www10.informatik.uni-erlangen.de/Teaching/Courses/SS2012/CPP/…
-
从幻灯片#5 开始,我假设写这篇文章的人从未听说过“模拟”的概念及其在单元测试中的用途。顺便说一句,使用 all-nodes-use-one-(super)class 方法会使讨论的问题变得毫无意义,因为不会有那些循环的类依赖关系。
标签: c++ c compiler-construction