3

I encountered a problem with two classes knowing each other when I was trying to create a directory structure similar to this:

Directory structure example

Here's my Base class which includes the common elements of File and Folder. Notice that I've left out getters and setters, constructors and destructors, #includes and #defines and other non-related methods and attributes (=nearly everything) for the sake of this question:

class Base {
    private:
        string m_name;
        /* Both File and Folder have a parent,
         * but the parent can only be a Folder */
        Base* m_parent;
};

Here's the class Folder which works just fine:

class Folder : public Base {
    public:
        virtual void addChild(Base* child);
        virtual void removeChild(Base* child);
    private:
        vector<Base*> m_children;
};

And then the File class has nothing new (other than some file related stuff which is unrelated to my question so I've left them out):

class File : public Base {
};

Now the header files look ok, nothing weird going on. However, this is how my constructor's should look like:

Base::Base(string name, Base* parent) { ... }
File::File(string name, Base* parent) { ... }
// parent should be of type Folder for Files too
Folder::Folder(string name, Folder* parent) { ... }

The problem is obvious. First of all, the parent should ALWAYS be a Folder, it can't be a File. However, I have to use Base since File and Base obviously can't know Folder.

Also, since my Base and File don't know Folder, they can't call it's addChild(Base* child); method:

File::File(string name, Base* parent)
: m_name(name), m_parent(parent)
{
    if (parent) {
        parent->addChild(this); // Base doesn't have addChild()-method
    }
}

I'm getting a headache from thinking, how can I get around this problem?

EDIT: I don't want a hacky way to get the result I'm looking for, I want to find the bug in my design. How's this stuff designed for windows or unix?

  • 1
    What is the use of Base exactly then? Folder's the only thing in your structure, File the only concrete leaf. Why would they need a common base? – Mat Apr 28 '13 at 11:53
  • 1
    The map is not the territory. Throw the inheritance away. Wrap functions common to file and folder in an interface. – Tony Hopkinson Apr 28 '13 at 11:56
  • @Mat Apologies for my extremely late answer, I just ran into someone else having this same problem and remembered this question of mine. They "need" a common base class cause they're 90% related, and if they ain't got a common base class, how am I supposed to create a vector `m_children` inside a folder? It would have to contain two different types, `File`s and `Folder`s. –  Jun 10 '13 at 14:30

1 Answers1

4

Try this:

class Folder;

class Base {
    protected:
        Base(const string &name, Folder *parent);
    private:
        string m_name;
        Folder *m_parent;
    //no add or remove should go here
};

class Folder : public Base {
    public:
        Folder(const string &name, Folder *parent)
        :Base(name, parent)
        {
        }
        void addChild(Base* child);
        void removeChild(Base* child);
    /*...*/
};

class File : public Base {
    public:
        File(const string &name, Folder *parent)
        :Base(name, parent)
        {
        }
};

inline Base::Base(const string &name, Folder *parent);
:m_name(name), m_parent(parent)
{
    if (parent) {
        parent->addChild(this); // no problem!
    }
}
rodrigo
  • 94,151
  • 12
  • 143
  • 190