C++ 前向声明和递归包含
C++ forward declaration and recursive includes
我有 8 个文件 FileSystem.cpp
、Node.cpp
、Directory.cpp
和 File.cpp
以及它们的 header hpp
个文件。
这是内存文件系统的基本模型。
class FileSystem
负责创建根目录 Directory
,它有自己的节点,也就是文件或目录。
对于 Directory
和 File
,class Node
是 parent class。我需要将 Node
包含到要继承的两个文件中,但是在节点 class 实现中,我需要访问 File
和 Directory
来执行一些操作。如果我尝试进行转发声明,我将得到 class 成员的未定义引用。我读了一些关于这个的文章,但我无法用 headers 解决我的问题。在 C++ 中解决此类问题的正确方法是什么。 How/should我用header解决这种问题?
请注意我的背景不同,所以我认为在 c++ 上遗漏了一些关于 headers 和递归声明的内容。
这里是这些文件的来源。
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];
}
}
#include "Directory.cpp"
#include "File.cpp"
我建议不要将源文件用作 headers。按照惯例编译源文件,但如果其中一个包含的文件被编译并与“Node.cpp”文件链接,那么你的程序是ill-formed,因为违反了一个定义规则。
If I try to make foward decleration, I will got undefined refernces of class members.
前向声明不应导致“class 成员的未定义引用”。你可能误会了什么。
What is the right approach for solving this kind of problem in c++.
简单地说,您需要按照依赖定义在依赖它们的定义之前的顺序对定义进行排序。当且仅当不存在这样的排序时,依赖图中存在循环,并且问题无法通过 re-ordering 定义来解决。在这种情况下,必须更改设计。
The class Node is parent class for both Directory and File. I need to include Node into both files to inherit from, but inside Node class implementation I need to access the File and Directory
这听起来像是糟糕的设计。或许可以实现,但不代表设计就一定好。
也就是说,以下顺序有效:
- 定义节点
- 定义目录和文件
- 定义使用目录和文件的函数
我有 8 个文件 FileSystem.cpp
、Node.cpp
、Directory.cpp
和 File.cpp
以及它们的 header hpp
个文件。
这是内存文件系统的基本模型。
class FileSystem
负责创建根目录 Directory
,它有自己的节点,也就是文件或目录。
对于 Directory
和 File
,class Node
是 parent class。我需要将 Node
包含到要继承的两个文件中,但是在节点 class 实现中,我需要访问 File
和 Directory
来执行一些操作。如果我尝试进行转发声明,我将得到 class 成员的未定义引用。我读了一些关于这个的文章,但我无法用 headers 解决我的问题。在 C++ 中解决此类问题的正确方法是什么。 How/should我用header解决这种问题?
请注意我的背景不同,所以我认为在 c++ 上遗漏了一些关于 headers 和递归声明的内容。
这里是这些文件的来源。
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];
}
}
#include "Directory.cpp" #include "File.cpp"
我建议不要将源文件用作 headers。按照惯例编译源文件,但如果其中一个包含的文件被编译并与“Node.cpp”文件链接,那么你的程序是ill-formed,因为违反了一个定义规则。
If I try to make foward decleration, I will got undefined refernces of class members.
前向声明不应导致“class 成员的未定义引用”。你可能误会了什么。
What is the right approach for solving this kind of problem in c++.
简单地说,您需要按照依赖定义在依赖它们的定义之前的顺序对定义进行排序。当且仅当不存在这样的排序时,依赖图中存在循环,并且问题无法通过 re-ordering 定义来解决。在这种情况下,必须更改设计。
The class Node is parent class for both Directory and File. I need to include Node into both files to inherit from, but inside Node class implementation I need to access the File and Directory
这听起来像是糟糕的设计。或许可以实现,但不代表设计就一定好。
也就是说,以下顺序有效:
- 定义节点
- 定义目录和文件
- 定义使用目录和文件的函数