【问题标题】:operator changing the argument of class for no reason (*int)运算符无故更改类的参数 (*int)
【发布时间】:2012-01-06 21:06:12
【问题描述】:

在我的班级文件中,我有:

class File
{
    std::vector<char> name, timeOfCreation, timeOfLastEdit, content;
    std::vector<char>::const_iterator* pPos, *pPosOfEnd;
    int *pSize;
    bool *pForcedSize;
    void setTimeOfLastEdit();
    int* indexOfLastChar, *indexOfCurrentChar;

    friend class Interface;
    friend class Directory;
public:
    File(std::string, int argSize = 0, std::string arg_content = 0); // constructor
    File(); // constructor
    File(const File&); // copy constructor
    ~File(); // destructor
    char* returnName(); 

    File& operator = (const File&);
    File operator += (const int);
    File operator -= (const int);
    File& operator ++ (); // prefix
    File& operator -- (); // prefix
    File operator ++ (int); // postfix
    File operator -- (int); // postfix

    bool operator ! ();

    int operator () (char*, int);

    friend  bool operator == (const File&, const File&);
    friend  bool operator != (const File&, const File&);
    friend  bool operator >= (const File&, const File&);
    friend  bool operator <= (const File&, const File&);
    friend  bool operator < (const File&, const File&);
    friend  bool operator > (const File&, const File&);

    friend std::istream & operator >> (std::istream&, File&);
    friend std::ostream & operator << (std::ostream&, File);

};

而我的操作符()是这样的:

int File::operator () (char* contentNextNBytes, int n)
{
    int i; int j = 0;
    std::vector<char>::const_iterator it = content.begin();
    for(j = 0; j < *indexOfCurrentChar; j++)
        ++it;

    for(i = 0; i < n; i++)
    {
        contentNextNBytes[i] = *it;
        if(i == *indexOfLastChar-1) 
        {
            contentNextNBytes[i+1] = '\0';
            *indexOfCurrentChar = i+1;
            return i+1;
        }
        ++it;
    }

    contentNextNBytes[i] = '\0';
    *indexOfCurrentChar = n;
    return n;
}

在我的另一个类Interface 中,我用int i = dir[index](buffer, n) 调用运算符(),其中n 是字节数,index 是目录中文件的索引。

现在,正如在运算符中实现的那样,*indexOfCurrentChar 指向的值应该(并且确实)成为从文件中提取的最后一个字符的位置。但是,当我再次使用 int j = dir[index](buffer, n1) 为相同的索引调用相同的运算符时,当程序进入运算符 {} 时,它再次将 *indexOfCurrentChar 的值更改为 0,而我的代码应该从最后一个字符继续并读取File 中接下来的 n1 个字节

为什么会这样? :(

这是我用来调用接口类中的运算符的部分代码:

 buffer = new char[n+1];
    k = d[index](buffer, n);
    std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
std::cout<<"\""<<buffer<<"\"";

Edit1:这里是我更改 indexOfCurrentChar 的地方:

1) 在赋值运算符 = 中(但是,我没有在我的 Interface 类中调用它) 2)在复制构造函数中(也不在接口类中使用它,它只是复制值) 3) 在文件构造函数中:

File::File()
{
    // stuff
    indexOfCurrentChar = new int;
} //I'm not setting its value, just allocating memory

4) 在文件构造函数中:

File::File(std::string arg_name, int arg_size, std::string arg_content)
{
     // stuff
     indexOfCurrentChar = new int;
     *indexOfCurrentChar = 0;
    //setting it to 0, but its just at creation time
}

5) 在 >> 运算符中 //获取文件内容

std::cout<<"Enter file content: ";
    *object.indexOfCurrentChar = 0;
    while( in.get(c) && c != '\n');
    i = 0;
    in.get(c);
    if(*(object.pSize) == 0)
    {
        while(c != '\n')
        {
            object.content.push_back(c);
            in.get(c);  
            ++i;
        }
        *(object.pSize) = (int)object.content.size();
        *(object.pPosOfEnd) = object.content.end();
        *object.indexOfLastChar = i;
    }
    else
    {
        i = 0;
        std::vector<char>::const_iterator it = object.content.begin();
        while(c != '\n')
        {
            if(i == *object.pSize)
            {
                *object.pPosOfEnd = it;
                *object.indexOfLastChar = i;
            }
            if(i >= *object.pSize)
            {
                in.get(c);
                continue;
            }
            object.content.push_back(c);
            in.get(c);
            ++i;
        }
    }


    *(object.pPos) = object.content.begin();

就是这样:)

Aaaaand 虽然我很抱歉向世界展示这个,但这是我丑陋的接口类方法。我所有的程序输入/输出都是通过 Interface.writeOutput 方法管理的,这里是:

Interface::Interface()
{
    menu = new char*[12];
    menu[0] = "Welcome, please select an option from the following, by pressing the respective numbers:";
    menu[1] = "1  Create a Directory\n2  Create a single File\n3  Exit program";
    menu[2] = "Ok, now please select a further option:";
    menu[3] = "Enter the number of Files you want to import: ";
    menu[4] = "Enter the files...";
    menu[5] = "1  Write out the Directory details\n2  Extract N bytes from a desired file\n3  Remove a file with desired name from the Directory\n4  Write content of a file\n0  Go back to the beginning";
    menu[6] = "Enter the index of the file: ";
    menu[7] = "Enter how many bytes to extract: ";
    menu[8] = "Content of the extracted bytes: ";
    menu[9] = "Enter the name of the file: ";
    menu[10] = "What do you want to do next?";
    menu[11] = "Please enter a regular number...";
}


void Interface::writeMenu()
{
    Error e;
    char c, tmp[5], name[30];
    int n, k, index, i, numDir;
    char *buffer; 
    int *haveReadFiles;

    std::cout<<menu[0];
    std::cout<<"\n\n";
startMenu: 
    std::cout<<menu[1];
    std::cout<<"\n\n";
    std::cin>>c;
    if((!isdigit(c)) || ( c != '1' && c!= '2' && c!='3'))
    {
        std::cout<<"\n"<<menu[11]<<"\n\n";
        goto startMenu;
    }
    if(c == '1')
    {
        std::cout<<"Enter the name of the directory: ";
        std::cin>>name;
        Directory d(name);
        std::cout<<"\n\n\nEnter number of files of directory: ";
        std::cin>>numDir;
        haveReadFiles = new int[numDir];
        if(!haveReadFiles)
        {
            e.writeToOutput(7);
            exit(1);
        }

        for(i = 0; i < numDir; i++)
        {
        haveReadFiles[i] = 0;   
            //std::cin.ignore(5,'\n');
        //  std::cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
            File f;
            std::cin>>f;
            d += f;
        }

    menu1:
        std::cout<<"\n\n"<<menu[2]<<"\n\n";
menuRepeat:
        std::cout<<menu[5];
        std::cout<<"\n\n";
        std::cin>>c;
        if(!isdigit(c) || (c != '1' && c!= '2' && c!='3' && c != '4' && c != '0'))
        {
            std::cout<<"\n"<<menu[11];
            goto menu1;
        }
        switch(c)
        {
        case '0': goto startMenu;break;
        case '1': std::cout<<d;break;
        case '2': 
            {
                menu2:
                std::cout<<"\n\n"<<menu[6];

                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menu2;
                    }
                index = atoi(tmp);
                menu3:
                std::cout<<"\n\n"<<menu[7];
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menu3;     
                    }
                n = atoi(tmp);


                buffer = new char[n+1];
                k = d[index](buffer, n);
                std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
                std::cout<<"\""<<buffer<<"\"";
            } break;
        case '3':
            {
                std::cout<<"\n\nEnter the name of the file: ";
                std::cin>>name;
                d -= name;
                std::cout<<"...file removed!\n";
                std::cout<<"Directory without the removed file looks like this: \n\n"<<d;
            }break;
        case '4': 
            {
                menuFF:
                std::cout<<"\n\nEnter the index of the desired file: ";
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menuFF;
                    }
                index = atoi(tmp);
                std::cout<<"\nHere's the content:\n";
                File ff = d[index];
                std::vector<char>::const_iterator iter = ff.content.begin();
                for(; iter < ff.content.end(); ++iter)
                {
                    std::cout<<*iter;
                }
                std::cout<<"\n\n";
            }
        }
        menu4:
        std::cout<<"\n\nWhat do you want to do now?\n\n1  Exit program\n2  Go back to start menu\n3  Do more stuff with your Directory\n\n";
        std::cin>>c;
        if((!isdigit(c)) || ( c != '1' && c!= '2' && c!='3'))
        {
            std::cout<<"\n"<<menu[11];
            goto menu4;
        }
        if(c=='1')
        {
            "Thank you, goodbye...";
            exit(0);
        }
        if(c=='2')
            goto startMenu;
        if(c=='3')
            goto menuRepeat;
    }
    else if(c=='2')
    {
        std::cout<<"Enter your file...\n";
        File g;
        std::cin>>g;
        menuZZ:
        std::cout<<"\n\nHere's what you can do with your file: \n\n1  Extract N bytes of content from it\n2  Write its content out\n3  Write its properties out\n4  Return to start menu\n\n";
        std::cin>>c;
        switch(c)
        {
        case '1':
            {

                menuYY:
                std::cout<<"\n\n"<<menu[7];
                std::cin>>tmp;
                for(i = 0; i < (int)strlen(tmp); i++)
                    if(!isdigit(tmp[i]))
                    {
                        std::cout<<"\n\n"<<menu[11];
                        goto menuYY;        
                    }
                n = atoi(tmp);
                buffer = new char[n+1];
                k = g(buffer, n);
                std::cout<<"Extracting of "<<k<<" bytes succeeded, and here is the content extracted:\n";
                std::cout<<"\""<<buffer<<"\"";
                std::cout<<"\n\n";
                goto startMenu;
            } break;
        case'2':
            {
                std::vector<char>::const_iterator it = g.content.begin();
                for(; it < g.content.end(); ++it)
                {
                    std::cout<<*it;
                }
                std::cout<<"\n\n";
            }
        case'3':
            {
                std::cout<<g<<"\n\n";
                goto startMenu;
            } break;
        case'4': 
            {
                std::cout<<"\n\n";
                goto startMenu;
            } break;
        default:
            {
                std::cout<<menu[11];
                goto menuZZ;    
            }

        }
    }
    else
    {
        std::cout<<"Thank you, goodbye... ";
        exit(0);
    }
}

编辑2:

最后但同样重要的是Directory::operator [] implementation

在标题中:File&amp; operator [] (int);

实施:

 File& Directory::operator [] (int index)
{
    std::vector<File>::const_iterator i = arr.begin();
    for(int j = 0; j < index; ++j)
        ++i;
    File* temp = new File;
    *temp = *i;
    return *temp;
    delete temp;
}

好好享受吧^^

【问题讨论】:

  • 您确定第二次使用的是同一个索引吗?
  • 您是否更改了*indexOfcurrentChar 指向您两次operator() 调用之间的某个位置?
  • @Meysam 是的,考虑到它正确地写出内容,只是从头开始,而应该从上一次提取结束时开始
  • @Tony The Lion 我很确定我没有,但我想这就是代码中发生的事情,可能是由于运算符 [],但我对此表示怀疑......
  • 在构造函数中,indexOfCurrentChar = 0 应改为 *indexOfCurrentChar = 0

标签: c++ class pointers operator-overloading arguments


【解决方案1】:

我的猜测是问题出在Directory 类以及它存储和返回File 对象的方式上。例如,如果Directory::operator[] 返回一个File 而不是File &amp;,那么对返回对象所做的任何更改都不会持久化到Directory 的内部副本中,因此连续调用两次喜欢

int i = dir[index](buffer, n);
int j = dir[index](buffer, n1);

实际上导致File::operator() 在两个不同的临时File 对象上被调用。这可以解释为什么*indexOfCurrentChar 的值不是您所期望的。

编辑

现在您已经展示了Directory::operator[] 的实现,我可以自信地说我的怀疑是正确的。即使您更改了Directory::operator[] 的签名,使其现在返回File &amp;,您的实现仍然不会按照您希望的方式运行,因为它没有返回对正确File 对象的引用( Directory 对象的内部副本)。三种说法

File* temp = new File;
*temp = *i;
return *temp;

创建Directory 对象的内部File 对象的新副本并返回对其的引用,因此对返回的File 对象的成员变量所做的任何更改都不会反映在@987654341 的相应条目中@向量。由于vector::operator[]返回一个引用,所以将Directory::operator[]的body改为简单

return arr[index];

应该给你想要的行为。

我可能还应该注意到,您当前的Directory::operator[] 实现会泄漏内存:delete temp; 永远不会运行,因为return *temp; 会导致控制权离开函数。

【讨论】:

  • 不,我测试过,这不是问题的原因。
  • @Meysam 你怎么能测试这个?你有Directory 类的源代码吗?
  • 你是对的。我的假设是 dirFile 对象的数组。正如你所说,operator[] 的实现在这里很重要:)
  • 实际上,我现在相当确定这是问题所在,基于海报的other questions 之一中显示的Directory 类的定义。
  • @chess007 是的,它只返回了文件,应该是这样的吗? File&amp; Directory::operator [] (int index) { std::vector&lt;File&gt;::const_iterator i = arr.begin(); for(int j = 0; j &lt; index; ++j) ++i; File* temp = new File; *temp = *i; return *temp; delete temp; } 我已将 [] 运算符更改为返回 File&amp;,但问题仍然存在.. 你认为它现在可以正确返回引用吗?
【解决方案2】:

我建议更换

 if(i == *indexOfLastChar-1)

 if(i == (*indexOfLastChar)-1)

我认为您正在读取 'indexOfLastChar' 之前的值并将其与 i 进行比较。

【讨论】:

  • 刚刚做了,不幸的是还是一样的:(
  • 取消引用运算符 (*) 在减法运算符 (-) 之前求值,减法运算符在 == 运算符之前求值。所以我认为这个改变不会有什么不同:en.cppreference.com/w/cpp/language/operator_precedence
  • indexOfCurrentChar = n; / 不应该是 */ *indexOfCurrentChar += n;
【解决方案3】:

我已经发布了这个作为评论,但我认为

indexOfCurrentChar = n; 

应该是

 *indexOfCurrentChar += n; 

【讨论】:

  • 是的,应该感谢,但它不能解决我当前的问题:(
猜你喜欢
  • 2017-06-04
  • 1970-01-01
  • 2011-06-07
  • 2018-06-30
  • 2018-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多