【发布时间】:2014-07-14 22:08:54
【问题描述】:
我正在制作一个玩具程序来从字符串创建类(例如,我将其输入为“test1 test2”,它会生成 test1.cpp、test1.h、test2.cpp、test2.h)
动作发生在这个函数中:
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames.good()){
issClassNames >> sClassName;
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str()), std::ios::app);
std::ofstream header(headerName.c_str()), std::ios::app);
//source << "#include \"" << headerName << "\"";
source.close();
header.close();
}
}
return returnValue;
}
文件以附加模式打开,以确保不会意外覆盖任何已经存在的类。
我最近返回该程序以包含一些附加功能 - 特别是,旧版本仅创建了两个空文件,我想对其进行修改以创建具有必要定义和包含的文件,因此我不必手动执行并每次添加它们。这揭示了意外的行为 - 最后一个类将任何文本添加两次。
在上面的代码示例中,我已经注释掉了我开始处理的行,但是当我不注释掉它时,我会得到这样的行为:
input:
classmaker.exe test1 test2
output:
test1.h
test2.h
test1.cpp //(Which contains: #include "test1.h")
test2.cpp //(Which contains: #include "test2.h"#include "test2.h"
我的猜测是我的while(issClassNames.good()) 会返回一个带有最后一个类名的额外时间(因此再次将字符串附加到源文件),但我不确定是什么行为导致了这种情况。
目前提出的解决方案:
- 在以
ofstream模式打开之前,测试是否已存在试图以ifstream模式打开的文件。 (问题:不能解决运行while一次模式而不是必要的问题) - 删除附加模式。 (问题:有覆盖已经存在的类的风险,仍然不能解决 while-loop 问题)
- 在 while 循环中使用条件测试,不要在上次运行时打开文件,例如将当前类名与上一个类名进行比较,如果相等则中止。问题:不知道如何检查这是否是最后一次运行,除了cludgy“这与上次的类名相同吗?”如果输入字符串是“test1 test1 test2”,测试也可能会过早中止
编辑
我意识到:不是真的 istringstream.good() 比预期返回 true 一次,而是它的评估结果如下:
input: "test1 test2"
evaluation:
good = true; extract next to string //(succeeds, overwrites empty string with "test1")
good = true; extract next to string //(succeeds, overwrites "test1" with "test2")
good = true; extract next to string //(fails, Doesn't overwrite "test2")
good = false; break loop.
编辑 2 + 3
这很容易解决。谢谢大家。不幸的是,我只能将一个答案标记为已接受,因此我选择了第一个发布的答案,但我感谢您的帮助。
完整的最终程序:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void makeClassesFromStdInput();
void makeClassesFromParameter(int argc, const char** argv);
bool makeClassesFromString(std::string classNames);
int main(int argc, const char** argv){
switch (argc) {
case 0: //This shouldn’t happen
break;
case 1:
//This will keep making classes from the CLI until
//the user breaks the process.
makeClassesFromStdInput();
break;
default:
//This will make classes from the parameters passed
//to the program except the first parameter which is
//assumed to be the program name.
makeClassesFromParameter(argc, argv);
break;
}
return 0;
}
void makeClassesFromStdInput(){
std::cout << "Input class name and press enter.\nWhitespace delimits class names.\nA blank line ends the process.\n>";
bool running = true;
std::string classNames;
while(running){
std::getline(std::cin, classNames);
running = makeClassesFromString(classNames);
}
}
void makeClassesFromParameter(int argc, const char** argv){
std::string classNames = "";
for(int i = 1; i<argc; i++){
classNames += argv[i];
classNames += " ";
}
makeClassesFromString(classNames);
}
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames >> sClassName){
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str(), std::ios::app);
std::ofstream header(headerName.c_str(), std::ios::app);
source << "#include \"" << headerName << "\"";
//Header is slightly more involved because we want all capital letters
for (std::string::size_type i=0; i<headerName.length(); ++i){
if(headerName[i] == '.'){
headerName[i] = '_';
}
else{
headerName[i] = toupper(headerName[i]);
}
}
header << "#ifndef __" << headerName << "\n"
<< "#define __" << headerName << "\n"
<< "\n"
<< "\n"
<< "#endif";
source.close();
header.close();
}
}
return returnValue;
}
【问题讨论】:
标签: c++ string while-loop