【问题标题】:Delegating Constructors with Inheritance in C++ FAT Filesystem Emulation在 C++ FAT 文件系统仿真中使用继承委托构造函数
【发布时间】:2015-07-28 13:39:56
【问题描述】:

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

  • Sdisk(通过字符串格式化磁盘到文件输出)。
  • Filesys(写入 FAT 和根目录)。
  • Shell(提供执行各种文件系统操作的能力。)

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

我决定使用调试器找出问题所在,并确定我在 Shell 构造函数中传递给 Sdisk 默认构造函数的值不正确。我开始挖掘并发现在当前类构造函数中调用另一个类构造函数被称为:“委托”或“构造函数链接”。我不知道。我发现您必须“从初始化列表中使用它,而不是从构造函数主体中使用它”。

我为 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 而不是 Filesys 继承 Sdisk。然后在 Filesys 构造函数中进行检查并调用 Sdisk。问题是当我将 Sdisk 继承到 FIlesys 时,它并没有说明它是一个类。我#include“Sdisk.h”和我只是不确定什么是最好的选择。

标签: c++ shell oop constructor fat


【解决方案1】:

问题出在这里:

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

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

其他说明:

  • 在您的 shell 构造函数中,您还使用 mem-initializer Filesys(disk) 初始化基类子对象。我在您的代码 sn-p 中找不到有效的 disk。但是当您遇到运行时问题而不是编译错误时,我想它只是在复制和粘贴中丢失了。

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

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

出于这些原因,我宁愿选择类似的东西:

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 

【讨论】:

  • 你是对的。我删除了它,而是试图找出一种将这三个参数传递给 Filesys 的方法,Filesys 又将它们传递给 Sdisk。我想调用Shell,用Sdisk做磁盘,然后用Filesys建文件系统。我不知道如何用一个类继承两个类。
  • 你可能不想继承。您的Shell 对象可能只需要一个指向Filesys 对象的引用或指针。或者甚至是Filesys 对象的集合。
【解决方案2】:

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

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 没有任何成员变量,因此它不能保持任何状态(我几乎可以肯定它不是有意的)......等等。

【讨论】:

  • 我明白了。我更正了无限递归,但没有解决使用临时值的问题。我应该调用 Sdisk 从 Shell 构建磁盘,然后在 Sdisk 中调用 Filesys 来构建文件系统。 shell 的默认构造函数应该通过调用 Sdisk 或 Filesys 来构建文件系统。我不确定是哪个。然后shell有各种功能来操作文件系统。 Shell 继承了 Filesys,因为它使用了各种功能。但我不明白为什么我们不继承 Sdisk。我不能这样做,因为我必须在 Sdisk 中继承两个类。
  • 默认参数也在我的main中:Shell("disk",256,128);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-16
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多