gpt4 book ai didi

c++ - 设计文件夹/文件系统?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:20:43 26 4
gpt4 key购买 nike

我正在尝试创建类似于大多数操作系统中使用的文件夹/文件系统。
基本上,我已经确定应该使用三个类。 FileFolder和一个公共(public)基类。为了创造力,我们将其称为Common
这就是我认为这三个标题的外观:

普通

class Common {
string m_name; // all files and folders have a name
Folder* m_parent; // all files and folders can have a parent

public:
virtual void open() = 0; // executed when folder or file is opened by user
virtual void draw() const; // all files and folders can be printed
virtual void setParent(Folder* parent);
virtual Folder* getParent() const;
};

文件夹.h
class Folder : public Common {
vector<Common*> m_children; // folders can contain other files and folders
// whereas files cannot

public:
virtual void open(); // folder opens; basically shows the content
virtual void draw() const; // folder draws differently
};

文件
class File : public Common {
// not really "files", they just call a function when opened
funcptr m_openAction;

public:
virtual void open(); // calls m_openAction() when opened
};

如您所见,问题在于我的基类 Common应该能够知道它的子类 Folder,这是不良行为,不应该这样做(至少根据我的老师说)。
这使我无法像计划的那样对系统进行编码。

这样的系统应该如何设计?

最佳答案

您现有的设计不需要Common来“知道其子类Folder”。
它只需要Common header 来声明存在这样的类
作为Folder:

class Folder; // Forward declaration

class Common {
string m_name; // all files and folders have a name
Folder* m_parent; // all files and folders can have a parent

public:
virtual ~Common(); // Don't forget virtual destructor!
virtual void open() = 0; // executed when folder or file is opened by user
virtual void draw() const; // all files and folders can be printed
virtual void setParent(Folder* parent);
virtual Folder* getParent() const;
};

这里没有依赖周期。

如果出于某种学术原因,您必须拥有一个甚至没有
提及任何子类,则可以使多态基类如下所示:
class Node {
string m_name; // all files and folders have a name
Node* m_parent; // all files and folders can have a parent

public:
virtual ~Node(); // Don't forget virtual destructor!
virtual void open() = 0; // executed when folder or file is opened by user
virtual void draw() const; // all files and folders can be printed
virtual void setParent(Node* parent);
virtual Node* getParent() const;
};

通过这种设计, setParent(Node* parent)方法将具有
包括运行时检查,以确保 Node *参数 parent实际上是一个 Folder *,例如
Folder *pf = dynamic_cast<Folder *>(parent);

在这种情况下,它还需要非空返回类型,通过该类型
指示成功或失败。这是曲折的,而不是仅仅做出 class Folder的声明。

来解决OP的后续问题。

Inside Common's setParent() I have to call Folder's m_children; which results into an error. Even if I include folder.h in common.cpp, I can't access folder's private members. Any ideas? :'



我前面的回答仅限于向您显示什么“使您无法像您计划的那样对系统进行编码”
实际上没有。

您现在看到的问题是将某些文件夹 f设置为某些文件夹的父文件夹
节点 n不是节点(文件或文件夹)上的独立操作。 f只能
如果 n同时成为其中之一,则有效地成为 n的父项 f的子级。因此在 n.setParent(parent)中,与设置同时进行
您希望将 n.mParent == parent添加到 nparent->m_children;
但是节点 m_children无法访问 n

这个问题对您的设计是一个沉重的暗示。如果设置 parent 并添加 child
必须始终一起发生,那么它们实际上是相同的操作-set-parent-add-child
-只是调用方式不同:是从父级还是从子级调用的。如果有 Common提供 setParent(Folder *)的原因,那么同样好 Folder提供 addChild(Common *)的原因,并且它们都必须做相同的事情。

这是否表明 static void Common::link(Folder * parent, Common * child)可以更好地公开取代它们吗?也许是这样;但是你开始 Common::setParent(Folder *)
这是合理的;因此将其与 Folder::addChild(Common *)匹配也是合理的,
然后我们可以通过互相调用使他们做同样的事情。

那么,还要考虑由于 pCommon->setParent(pFolder)
相当于 pFolder->addChild(pCommon),您还需要
从其父节点移除节点;因为在您可以有效添加之前
父节点的节点,必须将其从其现有父节点中删除(如果有)。和
该操作很可能会给客户端代码带来好处;所以 Folder::removeChild(Common *)也是对 Folder接口(interface)。
Folder::addChild(Common * pnode)Folder::removeChild(Common * pnode)
您缺乏管理私有(private)成员 Folder::m_children的接口(interface)。

接下来,考虑到每种方法都必须
确定 pnode是否实际上是该文件夹的子级:不得添加
子文件夹到已经是子文件夹的文件夹中,并且您不能删除不是一个子文件夹的子文件夹。
因此 Folder::find(Common * pnode)也将很有用-至少对于实现而言
(私有(private)),也可能是客户代码(公开):您可以决定。

然后,考虑 Folder::find(Common * pnode)要求
另一种方法: bool Common::operator==(Common const & other)。这么说吧
如果节点具有相同的名称,则它们相等。
Common::clearParent()也浮现在脑海,但我将其搁置一旁。

这些想法足以满足以下实现要求,即
不完整,次优和不切实际,但说明了如何将我们所拥有的点结合起来
刚刚确定要通过成员访问障碍
仍在阻止你这是不切实际的,因为它忽略了
假定为动态对象的所有权的整体问题
由其方法的 Folder *Common *参数解决。
您可以自己处理(并且您可能希望进行调查)
std::shared_ptr
std::unique_ptr,即使
这些更多
超出您在本项目中应使用的高级设施)。

common.h
#ifndef COMMON_H
#define COMMON_H

#include <string>

#include <iostream>

class Folder;

class Common {
std::string m_name;
Folder* m_parent;

public:
explicit Common(std::string const & name)
: m_name(name),m_parent(nullptr){}
virtual ~Common(){};
virtual void open() { /*Whatever*/}
virtual void draw() const {/*Whatever*/}
virtual Folder* getParent() const { return m_parent; };
virtual void setParent(Folder* parent);
bool operator==(Common const & other) const {
return m_name == other.m_name;
}
bool operator!=(Common const & other) const {
return !(*this == other);
}
#if 1 // Testing
std::string const & name() const {
return m_name;
}
std::string parent() const;

virtual void list() const {
std::cout << name() << " (in " << parent() << ')' << std::endl ;
}
#endif
};

#endif // EOF

folder.h
#ifndef FOLDER_H
#define FOLDER_H

#include "common.h"
#include <vector>

class Folder : public Common {
std::vector<Common *> m_children;

std::vector<Common *>::iterator find(Common const * child) {
auto i = m_children.begin();
for ( ;i != m_children.end() && **i != *child; ++i) {}
return i;
}

public:
explicit Folder(std::string const & name)
: Common(name){}
virtual void open(){/*Whatever*/}
virtual void draw() const {/*Whatever*/}
void addChild(Common * child) {
auto par = child->getParent();
if (par && par != this) {
par->removeChild(child);
}
if (find(child) == m_children.end()) {
m_children.push_back(child);
m_children.back()->setParent(this);
}
}
void removeChild(Common const * child) {
auto where = find(child);
if (where != m_children.end()) {
m_children.erase(where);
}
}
#if 1 // Testing
void list() const {
std::cout << name() << " {" << std::endl;
for (Common const * child : m_children) {
child->list();
}
std::cout << '}' << std::endl;
}
#endif
};

#endif //EOF

file.h
#ifndef FILE_H
#define FILE_H

#include "common.h"

class File : public Common {
// Whatever
public:
explicit File(std::string const & name)
: Common(name){}
virtual void open(){/*Whatever*/};

};

#endif // EOF

common.cpp
#include "common.h"
#include "folder.h"

void Common::setParent(Folder* parent) {
auto par = getParent();
if (par && par != parent) {
par->removeChild(this);
}
m_parent = parent;
m_parent->addChild(this);
}

#if 1 // Testing
std::string Common::parent() const {
return m_parent ? m_parent->name() : "<null>";
}
#endif

一个测试程序:
#include "common.h"
#include "folder.h"
#include "file.h"

int main()
{
Folder *fo0 = new Folder("folder0");
File * fi0 = new File("file0");
File * fi1 = new File("file1");
fo0->addChild(fi0);
fi1->setParent(fo0);
fo0->addChild(fi0); // Duplicate
fi1->setParent(fo0); // Duplicate
// There are now 2 files in folder fo0
fo0->list();
Folder *fo1 = new Folder("folder1");
fo1->addChild(fi1);
fi0->setParent(fo1);
fo1->addChild(fi1); // Duplicate
fi0->setParent(fo1); // Duplicate
// There are now 0 files in folder fo0
// There are now 2 files in folder fo1
fo0->list();
fo1->list();
delete fo0;
delete fo1;
delete fi0;
delete fi1;
return 0;
}

关于c++ - 设计文件夹/文件系统?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17013321/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com