2017-06-02 106 views
0

我对Java和C有一些经验,但现在只是从C++开始。 我想写一种逻辑树:C++,基类如何包含子类作为成员并调用其方法

所有项都从一个抽象基类“Item”派生。 有些项目是容器,可以包含多个项目。它们来自课程“Block”。一个块可以包含其他块(这是递归的)。 它也有一个操作员信息 其他元素是可运行的,它们不包含其他项目。

到目前为止,我可以构建我的树(并且偶然地使用pugixml lib将它反映到/从一个xml文件中)。 但现在在我的应用程序中,我想轻松地沿着树“移动自己”。 问题是我需要保留一个指向容器的指针,所以我可以移回来。 (第一个块将具有 'nullptr')

,所以我必须:(当然也有,我这里不复制的#ifdef guardblocks)

在item.h

#include "block.h" //issue here! 

enum Item_t { ... }; 

class Item 
{ 
public: 
    Item(Block* parentBlock, int order_number, int loop_number=1); 
    virtual ~Item(); 

    virtual Item_t getItemSubClass() const = 0; //just for some kind of reflexivity hack for other function (here in this sample to show this is abstract) 

protected: 
    Block* m_parentBlock; 
    int m_order_number; 
    int m_loop_number; 
    int m_current_loop=0; 
private: 
}; 

在block.h:

#include "item.h" 
#include <string.h> 
#include <map> 
#include <iostream> 

enum Operator { undefined, serial, parallel }; 

//class Item; // <= forward declaration ? won't work ! 

typedef std::map<int, Item*>::const_iterator item_iterator_t; 

class Block : public Item 
{ 
public: 
    Block(Block* parentBlock, int order_number, std::string op_str, int loop_number=1); 
    virtual ~Block(); 

    void addSubItem(int index, Item* item); 
    const Item* getSubItem(int index) const; 

    item_iterator_t item_begin() const; 
    item_iterator_t item_end() const; 

    Operator getOperator(void) const; 
    virtual Item_t getItemSubClass() const override; 
protected: 
private: 
    Operator m_op; 
    std::map<int, Item*> m_subItems; 
}; 

问题在这里:

  • 项目需要包含block.h,因为它具有指向它的成员指针,并且它在cpp文件中的构造函数调用block.addSubItem()方法。

  • 块显然需要包含item.h,因为它源自它。

  • 当需要调用方法或从类继承时,前向声明是不够的(对于这两种情况)。

  • 我可以稍微改变设计,由于没有设置父/子关系到构造函数(这会工作得很好,但我在有趣的看到了解决这一继承/递归问题)

回答

2

当我在写我的问题时,我发现了一个解决方案。 我的问题是由于我的编码风格,我倾向于我的class.cpp文件只包含我的相应class.h文件,并将所有其他包含命令集中在标题中。 (最后却是也许不是一个好的做法)

  • 在block.h:(没有其他选择继承)

    #include "item.h" 
    
  • 在item.h:使用前声明

    class SeqBlock; 
    
  • in item.cpp:include both!

    #include "item.h" //optional as included in block.h but make it clear 
    #include "block.h" 
    

(不知道但是这是最好的解决方案,或者如果原设计有一个很大的缺陷)

+1

没有真正寻找到你的代码:这似乎是正确的道路要走。通常的规则是:只在头文件中包含真正必要的内容,尽可能使用前向声明。仅包含实施文件(.cpp)中的剩余内容。减少依赖性并加快编译时间(在较大的项目中)。 – Rene

+0

所以我以相反的方式(和错误的!)来做这件事。我现在必须纠正所有的标题,因为这个项目将会很大,我会按照你的建议,谢谢! – Pellekrino

+0

在这种情况下,另一个建议:始终在实现文件中首先包含相应的头文件。这样,如果头文件不是“自给自足的”,你很快就会得到编译器错误。 – Rene

相关问题