我使用了两个设计模式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;
}
答案 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);
其中_outputFile
是ofstream
类型的成员,而outputFile
是string
。
这使用了C ++ 11特性(流的rvalue赋值),从版本4.7.1开始,g ++没有实现。
据推测,我的想法是关闭_outputFile
并重新打开它:只需这样做,代码将更加便携:
// Add failure checking:
_outputFile.close();
_outputFile.open( outputFile );
此外,更具描述性的命名会很好......
编译上面会产生一些关于有符号/无符号比较和未使用的局部变量的警告。解决所有问题。使用Visual C ++构建最高实用警告级别-Wall
和g {+ /W4
,并使其完全编译。
即使它编写得很干净,也可能并且通常会出现逻辑错误。要根除这些,设计一组完全可重现的测试,并提供任何必要的测试数据。