0

Composite と Visitor の 2 つのデザイン パターンを使用しました。私は Composite に問題はありません。しかし、彼が入力と出力の派生クラスを書き始めたとき、いくつかのエラーが発生しました。解決策は見つかりませんでした。実際には、すべてがInputVisitorである場合は、 PrintVisitormain()だけが残りました。

これが私のコードです:

UPD:コードの一部を書き直しました。今はエラーはありませんが、端末を開くだけで何もしません...

PS多分私はパターンを適切に実装していませんでした。誰かがより良いアイデアを持っていますか?

#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;
}
4

3 に答える 3

0

このコードでは:

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

InputVisitor は *input です。accept 関数は、訪問者への参照を受け取ります。次のように変更します。

root->accept(*input);  //Here

コメントで言及したタイプミスを除けば、すべて問題ありません。

クラスの名前の前にあるすべてを削除するclassと、クラス名のつづりが間違っている場合にコンパイラが通知します。それ以外の場合は、「Visirot将来のある時点で名前が付けられたクラスがあり、現在何が含まれているかはあまり気にしません。

于 2013-01-19T12:35:46.720 に答える
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* InputVisitor& Visitor& BaseComponent::accept` から派生し、ポインターを取得するか、参照を渡すように呼び出しを変更しますInputVisitorVisitor, sois convertible toandis convertible to, but there is no conversion from a pointer-to-type into a reference-to-type. So either change

于 2013-01-19T12:36:07.980 に答える
0

最初の問題。

タイプミスVisirotが修正されたと仮定すると、152行目で

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

これは、T が予期される T へのポインターを渡します。

そのポインターを逆参照するだけです:

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

2番目の問題。

メインプログラムに同じ修正を適用するのは間違っています:

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;
}

これにより、初期化されていないポインターが逆参照され、Undefined Behaviorが生成されます。

そうしないでください。

たとえば、次のように書き直します。

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(そして、そこに必要な具象クラスに置き換えることもできます。)

3番目の問題。

144 行目で、ストリームに割り当てています。

_outputFile = ofstream(outputFile);

_outputFiletype のメンバでofstreamoutputFilestringです。

これは、バージョン 4.7.1 の時点で g++ が実装していなかった C++11 機能 (ストリームの右辺値割り当て) を使用します。

おそらく、アイデアはそれを閉じ_outputFileて再度開くことです: それを行うだけで、コードはより移植性が高くなります:

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

また、よりわかりやすいネーミングが良いでしょう...

指定されたコードに設定された一般的な問題。

上記をコンパイルすると、符号付き/符号なしの比較と未使用のローカル変数に関する多くの警告が生成されます。それをすべて修正します。-Wallg++ とVisual C++ を使用して、実用的な最高の警告レベルでビルドし、/W4問題なくコンパイルできるようにします。

論理エラーとテスト。

正常にコンパイルされた場合でも、論理エラーが発生する可能性があり、通常はそのまま残ります。それらを根絶するために、正確に再現可能な一連のテストを考案し、必要なテスト データをすべて用意します。

于 2013-01-19T12:45:55.427 に答える