在 C++ FAT 文件系统仿真中使用继承委派构造函数

Delegating Constructors with Inheritance in C++ FAT Filesystem Emulation

我目前正在用 C++ 创建 FAT 文件系统。我有三个 classes:

在每次 class 编码期间,我编写了 Sdisk 和 Filesys 构造函数的简单主要初始化。现在,当我测试 Shell 的默认构造函数时,我正在编写 Shell,我遇到了内存问题。具体来说:EXC_BAD_ACCESS(code=1 address=0xfffffffffffffff....).

我决定使用我的调试器找出问题所在,并确定我在 Shell 构造函数中传递给 Sdisk 默认构造函数的值不正确。我开始挖掘,发现在当前 classes 构造函数中调用另一个 classes 构造函数被调用:"Delegating" 或 "Constructor Chaining"。我不知道。我发现你必须 "use it from the initialization list, not from the constructor body"。

我为 Shell 创建了一个没有参数的额外构造函数。我需要做的是使用 Sdisk 的默认三个参数从 Shell 构造函数内部调用 Sdisk。但是当我尝试这样做时,我继续出现内存错误。我什至尝试不给 Shell 的默认构造函数任何参数,但只要我在 main 中调用它就会导致错误。

非常感谢有关此事的任何帮助!谢谢!

Here is my reference for Delegating Constructors

class Shell: public Filesys
{
    public:    
    Shell(string filename, int blocksize, int numberofblocks):Filesys(disk) {Filesys(filename,blocksize,numberofblocks);};                // creates the file system.
        int dir();              // call ls which lists all files
        int add(string file);   // add a new file using input from the keyboard.
        int del(string file);   // deletes the file
        int type(string file);  //lists the contents of file
        int copy(string file1, string file2);//copies file1 to file2
    friend class Sdisk;
    friend class Filesys;
};



class Sdisk
{
    public :
    Sdisk() { }

    Sdisk(string diskname);                                         // Default Constructor
    Sdisk(string diskname, int numberofblocks, int blocksize);
    int getblock(int blocknumber, string& buffer);
    int putblock(int blocknumber, string buffer);
    int getblocksize() {return blocksize; }                         // Returns the blocksize.
    int getnumberofblocks() { return numberofblocks; }              // Returns the number of blocks.
    string getfilename() { return diskname; }                       // Returns the disk name.
    friend class Shell;
    friend class Filesys;

    private :

    int numberofblocks;                                             // number of blocks on disk
    string diskname;                                                // file name of pseudo-disk
    string diskname1;
    int blocksize;                                                  // block size in bytes/the number of blocks.
};

  class Filesys
{
public:

    Filesys(Sdisk&);
    int fsclose();
    int newfile(string file);
    int rmfile(string file);
    int getfirstblock(string file);
    int addblock(string file, string block);
    int delblock(string file, int blocknumber);
    int readblock(string file, int blocknumber, string& buffer);
    int writeblock(string file, int blocknumber, string buffer);
    int nextblock(string file, int blocknumber);
    bool checkblock(string file, int blocknumber);
    vector<string> block(string buffer, int b);
    Sdisk disk;
    friend class Shell;

    private :

    int fssync();                   //writes the Root and FAT to the disk.
    string buffer;
    int rootsize;                   // maximum number of entries in ROOT
    int fatsize;                    // number of blocks occupied by FAT
    vector<string> filename;        // filenames in ROOT
    vector<int> firstblock;         // firstblocks in ROOT parallel
    vector<int> fat;                // FAT # of blocks
};

int main()
{   
    Shell("disk",256,128);
    string s;
    string command="go";
    string op1,op2;

    while (command != "quit")
    {
        command.clear();
        op1.clear();
        op2.clear();
        cout << "$";
        getline(cin,s);
        unsigned long firstblank = s.find(' ');
        if (firstblank < s.length()) s[firstblank]='#';
        unsigned long secondblank = s.find(' ');
        command=s.substr(0,firstblank);
        if (firstblank < s.length())
            op1=s.substr(firstblank+1,secondblank-firstblank-1);
        if (secondblank < s.length())
            op2=s.substr(secondblank+1);
        if (command=="dir")
        {
            cout << "dir" << endl;

            // use the ls function

        }
        if (command=="add")
        {
            // The variable op1 is the new file
            cout << "add" << endl;

        }
        if (command=="del")
        {
            cout << "del" << endl;
            // The variable op1 is the file
        }
        if (command=="type")
        {
            cout << "type" << endl;
            // The variable op1 is the file
        }
        if (command=="copy")
        {
            cout << "copy" << endl;
            // The variable op1 is the source file and the variable op2 is the destination file.
        }
        if (command=="exit")
        {
            cout << "Exiting now..." << endl;
            return 0;
        }

    }

    return 0;
}





Filesys::Filesys(Sdisk& sdisk):Sdisk(disk)
{
    this-> disk = sdisk;
    rootsize = disk.getblocksize()/12;
    fatsize = (disk.getnumberofblocks()*5) / (disk.getblocksize())+1;
    cout << "rootsize: " << rootsize << endl << "fatsize: " << fatsize << endl << "number of blocks: " <<  disk.getnumberofblocks() << endl << "getblocksize(): " << disk.getblocksize() << endl;

    for(int i=0; i<rootsize; i++)
    {
        filename.push_back("XXXXXX");
        firstblock.push_back(0);
    }

    int k= disk.getnumberofblocks();
    fat.push_back(fatsize + 2);

    for (int i = 0; i <= fatsize; i++)
    {
        fat.push_back(0);

    }

    for(int i = fatsize + 2; i < k; i++)

    {
        fat.push_back(i+1);
    }
    fat[fat.size()-1] = 0;
    fssync();
}


Sdisk::Sdisk(string disk)
{
    diskname = disk + ".dat";
    diskname1 = disk + ".spc";
    ifstream ifile(diskname1.c_str());

    if(ifile.is_open())
    {
        ifile >> numberofblocks >> blocksize;
        ifile.close();
    }

    else
    {
        cout << "Was unable to open the file" << endl;
    }
}

// Sdisk default constructor
Sdisk::Sdisk(string disk, int numberofblocks, int blocksize)
{
    this->diskname = disk + ".dat";
    this->diskname1 = disk + ".spc";
    this->numberofblocks = numberofblocks;
    this->blocksize = blocksize;
    fstream spcfile;
    fstream datfile;
    spcfile.open((this->diskname1).c_str(),ios::in | ios::out);
    datfile.open((this->diskname).c_str(),ios::in | ios::out);

    if (spcfile.good() && datfile.good())
    {
        cout << "The disk named: " << diskname.c_str() << " exists and is now ready to be written to." << endl;
    }
    else // .spc/.dat file creation.
    {
        cout << "The disk: " << diskname.c_str() << "could not be found. " << endl;
        cout << "Both the SPC and DAT file were not found. Creating both now. Please wait...." << endl;
        spcfile.open((this->diskname1).c_str(),ios::out);
        datfile.open((this->diskname).c_str(),ios::out);
        spcfile << numberofblocks << " " << blocksize;
        cout << "The SPC file " << diskname.c_str() << " was created" << endl;
        cout << "The DAT file " << diskname.c_str() << " was created" << endl;

        for (int i=0; i<numberofblocks*blocksize; i++)
        {
            datfile.put('#');           // Fills the file with '#' character.
        }
    }
    spcfile.close();
    datfile.close();
    return;
}

问题出在这里:

Shell(string filename, int blocksize, int numberofblocks) : Filesys(disk) 
{
   Shell(filename,blocksize,numberofblocks);
};

Shell 构造函数在主体中创建一个临时 shell 对象,它本身再次调用 Shell 构造函数,依此类推。所以你最终会得到一个无限递归和一个完整的堆栈。

其他备注:

  • 在您的 shell 构造函数中,您还使用内存初始化器 Filesys(disk) 初始化了基础 class 子对象。我在您的代码片段中找不到有效的 disk。但是当您遇到运行时问题而不是编译错误时,我想它只是在复制和粘贴过程中丢失了。

  • 你确定 Shell 应该继承自 Filesys 吗? IE。你能说你的 Shell 是一个 FAT 文件系统吗?如果稍后您决定使用 NTFS 或 EXT3 文件系统来丰富您的 Shell 支持的文件系统,您的 class 设计将如何发展?

  • 最后,块数和块大小不是文件系统的参数,而不是您在其顶部构建的 shell 吗?

出于这些原因,我宁愿选择:

class Shell
{
    string fname; 
    Filesys &fs;  
public:    
    Shell(string filename, Filesys &filesystem) 
        : fname(filename), fs(disk)
    { ... };                // creates the file system.
    ...
};

在这种情况下,您将创建 Shell:

Sdisk mydisk("drive1", 32768, 4096);  // disk data for the disk constructor
Filesys mysystem(mydisk);             // fs parameters for the fs
Shell myshell("A:", mysystem);        // higher level abstraction 

希望我做对了。你的代码中有很多问题。正如我在评论中所说,这非常糟糕:

Shell(string filename, int blocksize, int numberofblocks):Filesys(disk) {
   Shell(filename,blocksize,numberofblocks);
};

明显是无限递归。你说你需要从 Shell 内部调用 Sdisk 所以我猜你的意思是:

Shell(string filename, int blocksize, int numberofblocks):Filesys(disk) {
   Sdisk(filename,blocksize,numberofblocks);
};

但是,它对您没有任何帮助。这样的语法将创建一个临时的 Sdisk ,它将立即消失。你说你想使用默认参数,但你没有提供任何地方。

总的来说你的设计很糟糕。 类 之间的关系不明确,你最终得到了没有多大意义的奇怪解决方案。 IE。你为什么要调用这个构造函数? SdiskShell有什么关系? Shell 没有任何成员变量所以它不能保持任何状态(我几乎可以肯定它不是有意的)...等等