C ++前向声明和递归包括

时间:2020-10-28 03:57:27

标签: c++ g++ forward-declaration

我有8个文件FileSystem.cppNode.cppDirectory.cppFile.cpp及其标头hpp文件。

这是内存文件系统的基本模型。 类FileSystem负责创建根Directory,该根拥有自己的节点(即文件或目录)。

NodeDirectoryFile的父类。我需要在两个文件中都包含Node才能继承,但是在Node类实现中,我需要访问FileDirectory来执行一些操作。如果我尝试使人屈服,那么我将得到类成员的不确定引用。我读了一些有关此的文章,但无法解决标题问题。解决c ++中此类问题的正确方法是什么?我如何/应该使用标题解决此类问题?

请注意,我的背景不同,所以我认为在c ++上缺少有关标头和递归声明的内容。

这是这些文件的来源。

FileSystem.cpp

#include <string>
#include <vector>
#include <iostream>

using namespace std;

#include "Node.hpp"
#include "Directory.hpp"

class FileSystem
{
private:
    // methods

    // attributes
    string name;
    Directory *root;

    friend class Directory;

public:
    int get_fresh_uid()
    {
        return 10;
    }

    FileSystem(string in_name)
    {
        name = in_name;
        root = new Directory(this, get_fresh_uid(), "root", nullptr);
    }

    ~FileSystem() {
        
    }

    // accessors
    string get_name()
    {
        return name;
    }

    Directory *get_root()
    {
        return root;
    }

    friend ostream &operator<<(ostream &output, FileSystem &fs)
    {
        return output;
    }
};

Node.cpp

#include <string>

#include "Directory.cpp"
#include "File.cpp"
class FileSystem;

using namespace std;

class Node
{
protected:
    FileSystem *fs;
    int uid;
    string name;
    Directory *parent;
    Node(FileSystem *fs_in, int uid_in, string name_in, Directory *parent_in)
    {
            fs = fs_in;
            name = name_in,
            uid = uid_in;
            parent = parent_in;
    }

    virtual void print_to(ostream os, int num) = 0;

public:
    ~Node() {
        
    }

    // accessors
    string get_name()
    {
        return name;
    }

    // methods
    virtual bool is_directory() = 0;
    virtual Directory *to_directory() = 0;
    virtual File *to_file() = 0;
    virtual int size() = 0;
};

File.cpp

#include "Node.hpp"
#include "Directory.hpp"
#include "FileSystem.hpp"

class File : public Node
{
private:
    string content;
    ~File() {
        
    }

public:
    File(FileSystem *fs_in, int uid_in, string name_in, Directory *parent_in);

    // accessors
    void set_content(const string &value)
    {
        content = value;
    }
    // mutators
    string get_content()
    {
        return content;
    }
    // methods
    int size()
    {
        return content.size();
    }

    bool is_directory()
    {
        return false;
    }

    Directory *to_directory()
    {
        return nullptr;
    }

    File *to_file()
    {
        return this;
    }

    void print_to(ostream os, int num)
    {
        // os << "+ file: " << name << ", uid: " << uid << ", size: " << size << ", " << "content: " << content;
    }
};
 

Directory.cpp

#include "File.hpp"
#include "FileSystem.hpp"
#include "Node.hpp"

class Directory : public Node
{
private:
    Directory(FileSystem *fs_in, int uid_in, string name_in, Directory *parent_in);
    ~Directory();

    // attributes
    vector<Node *> children;
    
    // methods
    bool child_exists(string name)
    {
        for (int i = 0; i < children.size(); i++)
        {
            return children[i]->get_name() == name;
        }
    }

    friend class FileSystem;
public:
    // accessors
    string get_name() {
        return name;
    }
    
    //methods
    int size()
    {
        int sum;

        for (int i = 0; i < children.size(); i++)
        {
            Node *child = children[i];
            sum += child->size();
        }

        return sum;
    }

    bool is_directory()
    {
        return true;
    }

    Directory *to_directory()
    {
        return this;
    }

    File *to_file()
    {
        return nullptr;
    }

    File *add_file(string filename)
    {
        // check whether same name child node exists
        if (child_exists(filename))
            return nullptr;

        // create file
        File *new_file = new File(fs, fs->get_fresh_uid(), filename, this);
        // add file to the children vector
        children.push_back(new_file);
        return new_file;
    }

    Directory *add_directory(string dirname)
    {
        // check whether same name child node exists
        if (child_exists(dirname))
            return nullptr;

        // create file
        Directory *new_dir = new Directory(fs, fs->get_fresh_uid(), dirname, this);
        // add dir to the children vector
        children.push_back(new_dir);
        return new_dir;
    }

    bool remove_node(string name)
    {
        for (int i = 0; i < children.size(); i++)
        {
            if (children[i]->get_name() == name)
            {
                children.erase(children.begin() + i);
                return true;
            }
        }

        return false;
    }

    Node *find_node(string name)
    {
        for (int i = 0; i < children.size(); i++)
        {
            if (children[i]->get_name() == name)
                return children[i];
        }

        return nullptr;
    }

    void print_to(ostream os, int num)
    {
        // os << "+ directory: " << name << ", uid: " << uid << ", size: " << size;
    }

    friend ostream &operator<<(ostream &output, Directory &dir)
    {
        return output;
    }
};

Directory::~Directory()
{
    for (int i = 0; i < children.size(); i++)
    {
        delete children[i];
    }
}

1 个答案:

答案 0 :(得分:1)

#include "Directory.cpp"
#include "File.cpp"

我建议不要将源文件用作标题。按照常规方式编译源文件,但是如果其中一个包含的文件被编译并与“ Node.cpp”文件链接,则由于违反“一个定义规则”,您的程序格式错误。

如果我试图退位,我将得到类成员的不确定引用。

前向声明绝对不能引起“类成员的未定义引用”。您可能误会了一些东西。

在c ++中解决此类问题的正确方法是什么。

简单来说,您需要对定义进行排序,其中依赖的定义要先于依赖的定义排序。当且仅当这种排序不存在时,依存关系图中才会存在一个循环,并且无法通过重新定义定义来解决问题。在这种情况下,必须更改设计。

Node类是Directory和File的父类。我需要将Node包含在要继承的两个文件中,但是在Node类的实现内部,我需要访问文件和目录

这听起来像是糟糕的设计。可能可以实现,但这并不意味着设计一定很好。

也就是说,以下顺序有效:

  • 定义节点
  • 定义目录和文件
  • 定义使用目录和文件的功能