这个 C++ 程序我做错了什么?
What am I doing wrong with this C++ program?
我正在尝试用 C++ 为我的计算机科学 class 创建一个咨询辅助程序,但不断收到错误:[错误] 'state' 没有命名类型和 [错误] 'state' 未在此范围内声明。有人可以让我知道我需要做什么才能获得这个程序 运行。我在出现错误的 C++ 文件下方包含了代码片段。我还提供了该程序运行所需的其他 C++ 文件的代码和资源文件。谢谢。
menu.cpp:
#include "menu.h"
#include "Course.h"
#include "Courses.h"
/// <summary>
/// Print menu options to stdout
/// </summary>
/// <param name=""></param>
void printMenu(void) {
cout << "Menu:" << endl;
cout << " 1. Load Data Structure." << endl;
cout << " 2. Print Course List." << endl;
cout << " 3. Print Course." << endl;
cout << " 9. Exit" << endl << endl;
cout << "What would you like to do? ";
}
/// <summary>
/// Call various functions based on the user's choice.
/// </summary>
/// <param name="choice"></param>
/// <param name="courses"></param>
void handleChoice(int choice, Courses& courses) {
switch (choice) {
case 1: // load file
{
string filename;
auto state = cin.exceptions(); // setup exception handling for stdin
cin.exceptions(std::istream::failbit | state);
cout << "Please enter the name of the data file to load." << endl;
cin.ignore();
// if already loaded discard previous and start another
if (courses.getSize() > 0) {
courses.clear();
}
try {
getline(cin, filename); // get user input of filename
courses.loadFromCSV(filename);
}
catch (exception ex) {
cout << ex.what() << endl; // display what happened to console
}
cin.exceptions(state); // restore previous exception settings
}
break;
case 2: // print all courses with id and title in alphanumeric order
cout << "Here is a sample schedule:" << endl << endl;
courses.printAll();
break;
case 3: // print one course and its prerequisites
{
string courseId;
cout << "What course do you want to know about? ";
cin >> courseId;
courses.printCourse(courseId);
}
break;
case 9: // exit program
cout << "Thank you for using the course planner!" << endl;
break;
default: // invalid choice
cout << choice << "is not a valid option." << endl << endl;
break;
}
}
void commandLoop(void) {
int choice = 0;
Courses courses; // declaring here allocates the memory for the lifetime of the loop
cout << "Welcome to the course planner." << endl;
while (choice != 9) { // while not exit command
cout << endl;
printMenu();
cin >> choice; // wait for user input
handleChoice(choice, courses);
}
}
main.cpp:
#include "menu.h"
int main(int argc, char* argv[]) {
// calls the command loop with no command line arguments
commandLoop();
}
Courses.cpp:
#include "Courses.h"
void Courses::addCourse(const Course course) {
// if adding first element, push
if (getSize() == 0) {
append(course);
} // if last element is less than one being inserted, push
// useful if file is mostly sorted
else if (at(getSize() - 1).getId().compare(course.getId()) < 0) {
append(course);
}
else { // otherwise insert which requires a binary search and then moving elements to make room
size_t insertionPoint;
insertionPoint = binarySearch(course.getId());
if (insertionPoint != SIZE_MAX) {
insert(insertionPoint, course);
}
}
}
size_t Courses::binarySearch(const string key) const {
size_t midPoint = SIZE_MAX;
size_t lowPoint = 0;
size_t highPoint = getSize() - 1;
// if the points haven't crossed each other continue
// its possible for the highpoint to wrap around from zero to SIZE_MAX, stop when that happens
while (highPoint != SIZE_MAX && highPoint >= lowPoint) {
midPoint = (highPoint + lowPoint) / 2; // locate the midpoint
Course course = at(midPoint); // get value at midpoint
if (course.getId() < key) { // what we are looking for is in the lower half?
lowPoint = midPoint + 1;
}
else if (course.getId() > key) { // what we are looking for is in the upper half?
highPoint = midPoint - 1;
}
else {
return midPoint; // found a match
}
}
// even if not found this is the closest point for insertion
// caller is responsible for checking value to determine how used
return midPoint;
}
void Courses::printAll() const
{
// already sorted so print out all courses by id and title
for (size_t i = 0; i < getSize(); ++i) {
Course course = at(i);
cout << course.getId() << " " << course.getTitle() << endl;
}
}
void Courses::printCourse(const string courseId) const {
Course course = findCourse(courseId);
if (course.getId().compare(courseId) == 0) {
// found
course.print();
}
else {
// not found
cout << "Could not find course: " << courseId << endl;
}
}
void Courses::loadFromCSV(const string filename, const string deliminator /* = "," */) {
string line; // holds a single line read from the file
int lineNumber = 0; // maintains a count of which line number in file we are on
ifstream inputFile(filename.c_str()); // open input file
if (inputFile.is_open())
{
while (inputFile.good())
{
// read line from file
getline(inputFile, line);
if (line != "") {
++lineNumber;
auto tokens = splitString(line, deliminator); // split line into tokens by deliminator
// check if there at least 2 tokens, id and title
if (tokens.size() < 2) {
cout << "Error: Line format error, expected 2 or more tokens, got ";
cout << tokens.size() << " tokens, line number: " << lineNumber << endl;
// skip line we cannot parse
continue; // while (inputFile.good())
}
Course course;
course.setId(tokens[0]);
// check if course is already loaded
Course duplicateCourse = findCourse(course.getId());
if (duplicateCourse.getId() != "") {
cout << "Warning: Duplicate course detected, line number: ";
cout << lineNumber << endl;
// dont add duplicate
continue; // while (inputFile.good())
}
// we can parse and not a duplicate so set the rest of the properties
course.setTitle(tokens[1]);
// check for any prerequisites and add to course
for (size_t i = 2; i < tokens.size(); ++i) {
string prerequisiteId = tokens.at(i);
// only add if prerequisite is already loaded
Course courseExists = findCourse(prerequisiteId);
if (courseExists.getId() == "")
{
cout << "Warning: Prerequisite not found, course: " << course.getId();
cout << ", prerequisite: " << prerequisiteId << endl;
// not found, skip to next
continue; // for (size_t i ...
}
// found, add course
course.addPrerequisite(courseExists);
}
// add course to data structure
addCourse(course);
}
}
inputFile.close();
if (lineNumber == 0)
throw runtime_error("No Data in " + filename);
}
else
throw runtime_error("Failed to open " + filename);
}
Course Courses::findCourse(const string courseId) const {
size_t index = binarySearch(courseId);
if (index != SIZE_MAX) {
Course course = at(index);
if (course.getId().compare(courseId) == 0) {
// found
return course;
}
else {
// not found
return Course();
}
}
else {
// not found
return Course();
}
}
vector<string> Courses::splitString(const string input, const string delimiter) const {
string temp = input;
size_t pos = 0;
string token;
vector<string> returnValue;
while ((pos = temp.find(delimiter)) != std::string::npos) {
token = temp.substr(0, pos); // get token from input
returnValue.push_back(token); // add value to vector
temp.erase(0, pos + delimiter.length()); // remove the part we found and leave the unfound for next call to find
}
if (temp.length() > 0) {
returnValue.push_back(temp); // add last value to vector
}
return returnValue;
}
Course.cpp:
#include "Course.h"
void Course::print() const {
cout << id << ", " << title;
// check if there are prerequisites to display
if (prerequisites.size() > 0) {
cout << endl << "Prerequisites: ";
// display all
for (size_t i = 0; i < prerequisites.size(); ++i) {
cout << prerequisites.at(i).getId();
// if before last, add delimiter
if (i + 1 < prerequisites.size()) {
cout << ", ";
}
}
}
cout << endl;
}
Course.h:
#ifndef __PROJECT_TWO_COURSE_H
#define __PROJECT_TWO_COURSE_H
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class Course
{
private:
string id;
string title;
vector<Course> prerequisites;
public:
/// <summary>
/// Default constructor
/// </summary>
Course() {
}
/// <summary>
/// Accessor method for Id
/// </summary>
/// <returns></returns>
string getId() const {
return this->id;
}
/// <summary>
/// Accessor method for Title
/// </summary>
/// <returns></returns>
string getTitle() const {
return this->title;
}
/// <summary>
/// Mutator method for Id
/// </summary>
/// <param name="id"></param>
void setId(const string id) {
this->id = id;
}
/// <summary>
/// Mutator method for Title
/// </summary>
/// <param name="title"></param>
void setTitle(const string title) {
this->title = title;
}
/// <summary>
/// Add a prerequisite
/// </summary>
/// <param name="course"></param>
void addPrerequisite(const Course course) {
prerequisites.push_back(course);
}
/// <summary>
/// Display course Id, Title, and Prerequisites
/// to stdout
/// </summary>
void print() const;
};
#endif
Courses.h:
#pragma once
#ifndef __PROJECT_TWO_COURSES_H
#define __PROJECT_TWO_COURSES_H
#include <stdexcept>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include "Course.h"
using namespace std;
class Courses
{
private:
/// <summary>
/// Memory storage for the Course objects
/// </summary>
vector<Course> courses;
/// <summary>
/// High level, non-implementation specific method for adding a course
/// to the underlying datatype.
/// </summary>
/// <param name="course"></param>
void addCourse(const Course course);
/// <summary>
/// Called by addCourse
/// Appends a course to the end of the data type
/// Wraps the data type implementation
/// Should call addCourse instead of this
/// </summary>
/// <param name="course"></param>
void append(const Course course) {
courses.push_back(course);
}
/// <summary>
/// Called by addCourse
/// Inserts a course somewhere into the data type
/// Wraps the data type implementation
/// Should call addCourse instead of this
/// </summary>
/// <param name="position">index of insertion</param>
/// <param name="course">the course object to insert</param>
void insert(const size_t position, const Course course) {
vector<Course>::iterator iter;
iter = courses.begin() + position;
courses.insert(iter, course);
}
/// <summary>
/// Wraps the data type at() call
/// Use this instead of accessing the datatype directly
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
Course at(const size_t index) const {
return courses.at(index);
}
/// <summary>
/// Performs a Binary Search of the data type
/// The data type is expected to already be sorted
/// Returns the midpoint regardless of found/not found
/// in order to communicate the closest value
/// The caller is responsible for checking the return value
/// to determine a match or not. Caller should call getSize()
/// before calling only call if > 0
/// </summary>
size_t binarySearch(const string key) const;
/// <summary>
/// Calls binarySearch and then checks the return value
/// On match will return the course found
/// On no match will return a default Course object
/// </summary>
Course findCourse(const string courseId) const;
/// <summary>
/// Splits a string into a vector<string> of tokens by a delimiter
/// </summary>
vector<string> splitString(const string input, const string delimiter) const;
public:
/// <summary>
/// Clear all the data.
/// </summary>
void clear() {
courses.clear();
}
/// <summary>
/// Initialize the Courses object from a CSV file
/// </summary>
void loadFromCSV(const string filename, const string deliminator = ",");
/// <summary>
/// Print a specific course and its Prerequisites.
/// </summary>
void printCourse(const string courseId) const;
/// <summary>
/// Print all courses by Id and Title in alphanumeric order.
/// </summary>
void printAll() const;
/// <summary>
/// Wraps the data type size() call
/// Use this instead of accessing the datatype directly
/// </summary>
/// <returns></returns>
size_t getSize() const {
return courses.size();
}
};
#endif
ABCU 建议程序输入 (abcu.csv):
MATH201,Discrete Mathematics
CSCI300,Introduction to Algorithms,CSCI200,MATH201
CSCI350,Operating Systems,CSCI300
CSCI101,Introduction to Programming in C++,CSCI100
CSCI100,Introduction to Computer Science
CSCI301,Advanced Programming in C++,CSCI101
CSCI400,Large Software Development,CSCI301,CSCI350
CSCI200,Data Structures,CSCI101
如果代码
auto state = cin.exceptions();
给你错误
[Error] 'state' does not name a type
表示你在C++98模式下编译代码,其中auto
还没有使用类型推导。那时,你可以说auto int i = 0;
来表示i
是自动存储期限(反正没有auto
)。
https://en.cppreference.com/w/cpp/keyword/auto
所以select至少C++11作为语言标准。
我正在尝试用 C++ 为我的计算机科学 class 创建一个咨询辅助程序,但不断收到错误:[错误] 'state' 没有命名类型和 [错误] 'state' 未在此范围内声明。有人可以让我知道我需要做什么才能获得这个程序 运行。我在出现错误的 C++ 文件下方包含了代码片段。我还提供了该程序运行所需的其他 C++ 文件的代码和资源文件。谢谢。
menu.cpp:
#include "menu.h"
#include "Course.h"
#include "Courses.h"
/// <summary>
/// Print menu options to stdout
/// </summary>
/// <param name=""></param>
void printMenu(void) {
cout << "Menu:" << endl;
cout << " 1. Load Data Structure." << endl;
cout << " 2. Print Course List." << endl;
cout << " 3. Print Course." << endl;
cout << " 9. Exit" << endl << endl;
cout << "What would you like to do? ";
}
/// <summary>
/// Call various functions based on the user's choice.
/// </summary>
/// <param name="choice"></param>
/// <param name="courses"></param>
void handleChoice(int choice, Courses& courses) {
switch (choice) {
case 1: // load file
{
string filename;
auto state = cin.exceptions(); // setup exception handling for stdin
cin.exceptions(std::istream::failbit | state);
cout << "Please enter the name of the data file to load." << endl;
cin.ignore();
// if already loaded discard previous and start another
if (courses.getSize() > 0) {
courses.clear();
}
try {
getline(cin, filename); // get user input of filename
courses.loadFromCSV(filename);
}
catch (exception ex) {
cout << ex.what() << endl; // display what happened to console
}
cin.exceptions(state); // restore previous exception settings
}
break;
case 2: // print all courses with id and title in alphanumeric order
cout << "Here is a sample schedule:" << endl << endl;
courses.printAll();
break;
case 3: // print one course and its prerequisites
{
string courseId;
cout << "What course do you want to know about? ";
cin >> courseId;
courses.printCourse(courseId);
}
break;
case 9: // exit program
cout << "Thank you for using the course planner!" << endl;
break;
default: // invalid choice
cout << choice << "is not a valid option." << endl << endl;
break;
}
}
void commandLoop(void) {
int choice = 0;
Courses courses; // declaring here allocates the memory for the lifetime of the loop
cout << "Welcome to the course planner." << endl;
while (choice != 9) { // while not exit command
cout << endl;
printMenu();
cin >> choice; // wait for user input
handleChoice(choice, courses);
}
}
main.cpp:
#include "menu.h"
int main(int argc, char* argv[]) {
// calls the command loop with no command line arguments
commandLoop();
}
Courses.cpp:
#include "Courses.h"
void Courses::addCourse(const Course course) {
// if adding first element, push
if (getSize() == 0) {
append(course);
} // if last element is less than one being inserted, push
// useful if file is mostly sorted
else if (at(getSize() - 1).getId().compare(course.getId()) < 0) {
append(course);
}
else { // otherwise insert which requires a binary search and then moving elements to make room
size_t insertionPoint;
insertionPoint = binarySearch(course.getId());
if (insertionPoint != SIZE_MAX) {
insert(insertionPoint, course);
}
}
}
size_t Courses::binarySearch(const string key) const {
size_t midPoint = SIZE_MAX;
size_t lowPoint = 0;
size_t highPoint = getSize() - 1;
// if the points haven't crossed each other continue
// its possible for the highpoint to wrap around from zero to SIZE_MAX, stop when that happens
while (highPoint != SIZE_MAX && highPoint >= lowPoint) {
midPoint = (highPoint + lowPoint) / 2; // locate the midpoint
Course course = at(midPoint); // get value at midpoint
if (course.getId() < key) { // what we are looking for is in the lower half?
lowPoint = midPoint + 1;
}
else if (course.getId() > key) { // what we are looking for is in the upper half?
highPoint = midPoint - 1;
}
else {
return midPoint; // found a match
}
}
// even if not found this is the closest point for insertion
// caller is responsible for checking value to determine how used
return midPoint;
}
void Courses::printAll() const
{
// already sorted so print out all courses by id and title
for (size_t i = 0; i < getSize(); ++i) {
Course course = at(i);
cout << course.getId() << " " << course.getTitle() << endl;
}
}
void Courses::printCourse(const string courseId) const {
Course course = findCourse(courseId);
if (course.getId().compare(courseId) == 0) {
// found
course.print();
}
else {
// not found
cout << "Could not find course: " << courseId << endl;
}
}
void Courses::loadFromCSV(const string filename, const string deliminator /* = "," */) {
string line; // holds a single line read from the file
int lineNumber = 0; // maintains a count of which line number in file we are on
ifstream inputFile(filename.c_str()); // open input file
if (inputFile.is_open())
{
while (inputFile.good())
{
// read line from file
getline(inputFile, line);
if (line != "") {
++lineNumber;
auto tokens = splitString(line, deliminator); // split line into tokens by deliminator
// check if there at least 2 tokens, id and title
if (tokens.size() < 2) {
cout << "Error: Line format error, expected 2 or more tokens, got ";
cout << tokens.size() << " tokens, line number: " << lineNumber << endl;
// skip line we cannot parse
continue; // while (inputFile.good())
}
Course course;
course.setId(tokens[0]);
// check if course is already loaded
Course duplicateCourse = findCourse(course.getId());
if (duplicateCourse.getId() != "") {
cout << "Warning: Duplicate course detected, line number: ";
cout << lineNumber << endl;
// dont add duplicate
continue; // while (inputFile.good())
}
// we can parse and not a duplicate so set the rest of the properties
course.setTitle(tokens[1]);
// check for any prerequisites and add to course
for (size_t i = 2; i < tokens.size(); ++i) {
string prerequisiteId = tokens.at(i);
// only add if prerequisite is already loaded
Course courseExists = findCourse(prerequisiteId);
if (courseExists.getId() == "")
{
cout << "Warning: Prerequisite not found, course: " << course.getId();
cout << ", prerequisite: " << prerequisiteId << endl;
// not found, skip to next
continue; // for (size_t i ...
}
// found, add course
course.addPrerequisite(courseExists);
}
// add course to data structure
addCourse(course);
}
}
inputFile.close();
if (lineNumber == 0)
throw runtime_error("No Data in " + filename);
}
else
throw runtime_error("Failed to open " + filename);
}
Course Courses::findCourse(const string courseId) const {
size_t index = binarySearch(courseId);
if (index != SIZE_MAX) {
Course course = at(index);
if (course.getId().compare(courseId) == 0) {
// found
return course;
}
else {
// not found
return Course();
}
}
else {
// not found
return Course();
}
}
vector<string> Courses::splitString(const string input, const string delimiter) const {
string temp = input;
size_t pos = 0;
string token;
vector<string> returnValue;
while ((pos = temp.find(delimiter)) != std::string::npos) {
token = temp.substr(0, pos); // get token from input
returnValue.push_back(token); // add value to vector
temp.erase(0, pos + delimiter.length()); // remove the part we found and leave the unfound for next call to find
}
if (temp.length() > 0) {
returnValue.push_back(temp); // add last value to vector
}
return returnValue;
}
Course.cpp:
#include "Course.h"
void Course::print() const {
cout << id << ", " << title;
// check if there are prerequisites to display
if (prerequisites.size() > 0) {
cout << endl << "Prerequisites: ";
// display all
for (size_t i = 0; i < prerequisites.size(); ++i) {
cout << prerequisites.at(i).getId();
// if before last, add delimiter
if (i + 1 < prerequisites.size()) {
cout << ", ";
}
}
}
cout << endl;
}
Course.h:
#ifndef __PROJECT_TWO_COURSE_H
#define __PROJECT_TWO_COURSE_H
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class Course
{
private:
string id;
string title;
vector<Course> prerequisites;
public:
/// <summary>
/// Default constructor
/// </summary>
Course() {
}
/// <summary>
/// Accessor method for Id
/// </summary>
/// <returns></returns>
string getId() const {
return this->id;
}
/// <summary>
/// Accessor method for Title
/// </summary>
/// <returns></returns>
string getTitle() const {
return this->title;
}
/// <summary>
/// Mutator method for Id
/// </summary>
/// <param name="id"></param>
void setId(const string id) {
this->id = id;
}
/// <summary>
/// Mutator method for Title
/// </summary>
/// <param name="title"></param>
void setTitle(const string title) {
this->title = title;
}
/// <summary>
/// Add a prerequisite
/// </summary>
/// <param name="course"></param>
void addPrerequisite(const Course course) {
prerequisites.push_back(course);
}
/// <summary>
/// Display course Id, Title, and Prerequisites
/// to stdout
/// </summary>
void print() const;
};
#endif
Courses.h:
#pragma once
#ifndef __PROJECT_TWO_COURSES_H
#define __PROJECT_TWO_COURSES_H
#include <stdexcept>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include "Course.h"
using namespace std;
class Courses
{
private:
/// <summary>
/// Memory storage for the Course objects
/// </summary>
vector<Course> courses;
/// <summary>
/// High level, non-implementation specific method for adding a course
/// to the underlying datatype.
/// </summary>
/// <param name="course"></param>
void addCourse(const Course course);
/// <summary>
/// Called by addCourse
/// Appends a course to the end of the data type
/// Wraps the data type implementation
/// Should call addCourse instead of this
/// </summary>
/// <param name="course"></param>
void append(const Course course) {
courses.push_back(course);
}
/// <summary>
/// Called by addCourse
/// Inserts a course somewhere into the data type
/// Wraps the data type implementation
/// Should call addCourse instead of this
/// </summary>
/// <param name="position">index of insertion</param>
/// <param name="course">the course object to insert</param>
void insert(const size_t position, const Course course) {
vector<Course>::iterator iter;
iter = courses.begin() + position;
courses.insert(iter, course);
}
/// <summary>
/// Wraps the data type at() call
/// Use this instead of accessing the datatype directly
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
Course at(const size_t index) const {
return courses.at(index);
}
/// <summary>
/// Performs a Binary Search of the data type
/// The data type is expected to already be sorted
/// Returns the midpoint regardless of found/not found
/// in order to communicate the closest value
/// The caller is responsible for checking the return value
/// to determine a match or not. Caller should call getSize()
/// before calling only call if > 0
/// </summary>
size_t binarySearch(const string key) const;
/// <summary>
/// Calls binarySearch and then checks the return value
/// On match will return the course found
/// On no match will return a default Course object
/// </summary>
Course findCourse(const string courseId) const;
/// <summary>
/// Splits a string into a vector<string> of tokens by a delimiter
/// </summary>
vector<string> splitString(const string input, const string delimiter) const;
public:
/// <summary>
/// Clear all the data.
/// </summary>
void clear() {
courses.clear();
}
/// <summary>
/// Initialize the Courses object from a CSV file
/// </summary>
void loadFromCSV(const string filename, const string deliminator = ",");
/// <summary>
/// Print a specific course and its Prerequisites.
/// </summary>
void printCourse(const string courseId) const;
/// <summary>
/// Print all courses by Id and Title in alphanumeric order.
/// </summary>
void printAll() const;
/// <summary>
/// Wraps the data type size() call
/// Use this instead of accessing the datatype directly
/// </summary>
/// <returns></returns>
size_t getSize() const {
return courses.size();
}
};
#endif
ABCU 建议程序输入 (abcu.csv):
MATH201,Discrete Mathematics
CSCI300,Introduction to Algorithms,CSCI200,MATH201
CSCI350,Operating Systems,CSCI300
CSCI101,Introduction to Programming in C++,CSCI100
CSCI100,Introduction to Computer Science
CSCI301,Advanced Programming in C++,CSCI101
CSCI400,Large Software Development,CSCI301,CSCI350
CSCI200,Data Structures,CSCI101
如果代码
auto state = cin.exceptions();
给你错误
[Error] 'state' does not name a type
表示你在C++98模式下编译代码,其中auto
还没有使用类型推导。那时,你可以说auto int i = 0;
来表示i
是自动存储期限(反正没有auto
)。
https://en.cppreference.com/w/cpp/keyword/auto
所以select至少C++11作为语言标准。