c++ - C++ 前向声明和递归包含
问题描述
我有 8 个文件FileSystem.cpp
,Node.cpp
和它们Directory.cpp
的File.cpp
头hpp
文件。
这是内存文件系统的基本模型。类FileSystem
负责创建Directory
具有自己的节点(即文件或目录)的根。
该类Node
是Directory
和的父类File
。我需要包含Node
到两个文件中以继承,但在 Node 类实现中我需要访问File
andDirectory
来执行一些操作。如果我尝试进行前向声明,我将得到类成员的未定义引用。我读了一些关于这个的文章,但我无法解决我的标题问题。在 c++ 中解决此类问题的正确方法是什么。我如何/应该使用标题来解决这类问题?
请注意我的背景不同,所以我认为在 C++ 上遗漏了一些关于标头和递归声明的内容。
这里是这些文件的来源。
文件系统.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;
}
};
节点.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;
};
文件.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;
}
};
目录.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"
我建议不要使用源文件作为标题。传统上,源文件是按惯例编译的,但如果其中一个包含的文件被编译并与“Node.cpp”文件链接,那么由于违反了一个定义规则,您的程序格式错误。
如果我尝试进行前向声明,我将得到类成员的未定义引用。
前向声明永远不应导致“类成员的未定义引用”。你可能误会了什么。
在 c++ 中解决此类问题的正确方法是什么。
简单地说,您需要按照依赖定义在依赖它们的定义之前的顺序对定义进行排序。当且仅当这种排序不存在时,依赖图中存在一个循环,并且无法通过重新排序定义来解决问题。在这种情况下,设计将不得不改变。
Node 类是 Directory 和 File 的父类。我需要将 Node 包含到两个文件中以继承,但在 Node 类实现中我需要访问文件和目录
这听起来像是糟糕的设计。有可能实现,但这并不意味着设计一定是好的。
也就是说,以下顺序有效:
- 定义节点
- 定义目录和文件
- 定义使用 Directory 和 File 的函数
推荐阅读
- javascript - 根据创建的时间从对象数组中删除重复项
- html - 即使元素类名存在,也无法设置 HTML 元素
- mapbox - NavigationViewController 的问题 - SwiftUI
- oauth - vimeo api 在生成访问令牌时不返回用户凭据
- javascript - 如何使用 Google Docs API 将文本插入表格单元格?
- npm-start - 运行 npm start 命令时找不到模块错误
- .net - .NET 5 在 Jetson Nano / Ubuntu 上的安装问题
- c# - Unity VR 渲染纹理、场景空间渲染和混合层
- python - 为什么无论如何都会执行 else 条件?
- reactjs - 将按下/触摸事件应用于使用 Animated.View 制作的布局