无法将参数1从'PrintVisitor * const'转换为'Visirot&'

时间:2013-01-19 12:28:03

标签: c++ design-patterns composite typeconverter visitor-pattern

我使用了两个设计模式Composite和Visitor。我没有使用Composite.But,当他开始为输入和输出编写派生类时遇到了一些错误,我从未找到过的解决方案。虽然实际上,如果所有内容都是 InputVisitor ,那么只保留 PrintVisitor main()

这是我的代码:

UPD:我重写了部分代码。现在我没有错误,但它只打开终端,而不是在做... ...

P.S。也许我没有正确实现模式。有人有更好的主意吗?

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

class BaseComponent {
public:
    virtual void add(BaseComponent *)=0;
    virtual void accept(class Visitor &)=0;
};

class Card :public BaseComponent {
public:
    Card (string bookName, vector<string> authors, int year): _bookName(bookName), _authors(authors), _year(year) {}

    string getBookName() const {
        return _bookName;
    }
    vector<string> getAuthors() const {
        return _authors;
    }
    int getYear() const {
        return _year;
    }

    void setBookName(string bookName) {
        _bookName = bookName;
    }
    void setAuthors(vector<string> authors) {
        copy(authors.begin(), authors.end(), _authors.begin());
    }
    void setYear(int year) {
        _year = year;
    }

    void add(BaseComponent *){}
    void accept(class Visitor &);
private:
    string _bookName;
    vector<string> _authors;
    int _year;
};

class Folder :public BaseComponent {
public:
    Folder(): _folderName(""), _parentFolder("") {}
    Folder(string parentFolder): _folderName(""), _parentFolder(parentFolder) {}

    string getFolderName() const {
        return _folderName;
    }
    string getParentName() const {
        return _parentFolder;
    }
    vector<BaseComponent*> getSubFolders() const {
        return _subFolders;
    }

    void setFolderName(string folderName) {
        _folderName = folderName;
    }
    void setParentFolder(string parentFolder) {
        _parentFolder = parentFolder;
    }

    void add(BaseComponent *component) {
        _subFolders.push_back(component); 
    }
    void accept(class Visitor &);
private:
    string _folderName;
    string _parentFolder;
    vector<BaseComponent*> _subFolders;
};

class Visitor {
public:
    virtual void visitCard(Card *)=0;
    virtual void visitFolder(Folder *)=0;
};

void Card::accept(class Visitor &visitor) {
    visitor.visitCard(this);
}

void Folder::accept(class Visitor &visitor) {
    visitor.visitFolder(this);
}

class InputVisitor :public Visitor {
public:
    InputVisitor(string file): _file(file){}

    void setFile(string file) {
        _file = file;
    } 

    void visitCard(Card *){}
    void visitFolder(Folder *folder){
        ifstream input(_file);

        string folderName;
        getline(input, folderName);
        folder->setFolderName(folderName);

        string fileName;
        while (!input.eof()) {
            input >> fileName;
            if (fileName == "----") {
                break;
            } else {
                Folder *subFolder = new Folder(folderName);
                InputVisitor *inputVisitor = new InputVisitor(fileName);
                subFolder->accept(*inputVisitor);
                folder->add(subFolder);
            }
        }
        while (!input.eof()) {
            string name, tempAuthor;
            vector<string> authors;
            int n, year;

            input >> name;
            input >> n;
            for (int i = 0; i<n; ++i) {
                input >> tempAuthor;
                authors.push_back(tempAuthor);
            }
            input >> year;
            Card *subBook = new Card(name, authors, year);
            folder->add(subBook);
        }
        input.close();
    }
private:
    string _file;
};

class PrintVisitor :public Visitor {
public:
    PrintVisitor(string outputFile): _outputFile(outputFile) {}

    void setOutputFile(string outputFile) {
        _outputFile = outputFile;
    }

    void visitFolder(Folder *folder) {
        ofstream output(_outputFile);
        output << folder->getFolderName() << endl << "\t";

        vector<BaseComponent*> subFolders = folder->getSubFolders();
        vector<BaseComponent*>::iterator it;
        for (it=subFolders.begin(); it!=subFolders.end(); ++it) {
            (*it)->accept(*this);
        }

        output.close();
    }
    void visitCard(Card *card) {
        ofstream output(_outputFile);
        output << "Book: " << card->getBookName() << endl
            << "Author(s): ";
        vector<string> authors = card->getAuthors();
        for (vector<string>::iterator it=authors.begin(); it!=authors.end(); ++it) {
            output << *it << " ";
        }
        output << endl << "Year: " << card->getYear();

        output.close();
    }
private:
    string _outputFile;
};


int main() {
    Folder root;
    root.accept(*(new InputVisitor("root.txt")));
    root.accept(*(new PrintVisitor("output.txt")));
    return 0;
}

3 个答案:

答案 0 :(得分:0)

在此代码中:

InputVisitor *input;
input->setFile("root.txt");
root->accept(input);  //Here

InputVisitor是*输入。您的接受函数会引用访问者。将其更改为:

root->accept(*input);  //Here
除了我在评论中提到的拼写错误外,一切都会好的。

如果删除类名称前面的所有class,编译器会告诉您何时出现拼写错误的类名。否则,它只会将其视为“将来某个时候会有一个名为Visirot的类,而我现在并不在乎它的内容。

答案 1 :(得分:0)

以下是BaseComponent::accept的声明:

virtual void accept(class Visirot &)=0;

这是电话:

root->accept(input);  //Here

以下是input的声明:

InputVisitor *input;

首先,BaseComponent::accept的声明显然有拼写错误; Visirot应该是Visitor

其次,accept需要Visitor&,但会使用InputVisitor*进行调用。 InputVisitor源自Visitor, so InputVisitor * is convertible to访问者* and InputVisitor&amp; is convertible to访客&amp; , but there is no conversion from a pointer-to-type into a reference-to-type. So either change BaseComponent :: accept`获取指针或更改呼叫以传递参考。

答案 2 :(得分:0)

第一个问题。

假设拼写错误Visirot已修复,那么在第152行你有

subFolders[i]->accept(this); //Here some probrem

传递指向T的指针,其中T是预期的。

只需取消引用指针:

subFolders[i]->accept(*this);

第二个问题。

在主程序中应用相同的修复程序错误

int main() {
    BaseComponent *root;
    InputVisitor *input;
    input->setFile("root.txt");
    root->accept(*input);  //Here
    PrintVisitor *output;
    output->setOutputFile("output.txt");
    root->accept(output); //And here
    return 0;
}

这取消引用未初始化的指针,产生未定义的行为

不要那样做。

将其重写为例如。

int main() {
    Folder root;
    InputVisitor input;
    input.setFile("root.txt");
    root.accept(input);  //Here
    PrintVisitor output;
    output.setOutputFile("output.txt");
    root.accept(output); //And here
}

(并且可能用你想要的任何具体类替换Folder。)

第三个问题。

在第144行,您要分配一个流:

_outputFile = ofstream(outputFile);

其中_outputFileofstream类型的成员,而outputFilestring

这使用了C ++ 11特性(流的rvalue赋值),从版本4.7.1开始,g ++没有实现。

据推测,我的想法是关闭_outputFile并重新打开它:只需这样做,代码将更加便携:

// Add failure checking:
_outputFile.close();
_outputFile.open( outputFile );

此外,更具描述性的命名会很好......

给定代码中设置的一般问题。

编译上面会产生一些关于有符号/无符号比较和未使用的局部变量的警告。解决所有问题。使用Visual C ++构建最高实用警告级别-Wall和g {+ /W4,并使其完全编译。

逻辑错误&amp;测试

即使它编写得很干净,也可能并且通常会出现逻辑错误。要根除这些,设计一组完全可重现的测试,并提供任何必要的测试数据。