これをデバッグしようとして高低を検索しましたが、これまでのところわかりません。
DataList.h という名前のファイルにクラス宣言があり、DataList.cc ファイルという名前のファイルにメソッドがあり、別の .cc ファイルにメイン プログラムがあります。
DataList.cc には、DataList.h をインクルードするための #include ヘッダーがあります。
私が走るたびに
g++ DataList.cc
Ubuntuターミナルでは、吐き出します
DataList.cc: In function ‘bool TransactOnce(int&, TRANS&, std::string&)’:
DataList.cc:395:2: error: ‘ListNodeT’ was not declared in this scope
DataList.cc:395:13: error: ‘nodeTPtr’ was not declared in this scope
DataList.cc:396:13: error: ‘headTrans’ was not declared in this scope
奇妙なのは、これらの型の変数を DataList.cc の他のメンバー関数のすべての場所で宣言しているということですが、コンパイラは上記以外のエラーを表示しません。私は、その1つの関数内の特定の宣言についてg ++が気に入らないことが何であるかを理解しようとしています。
「ListNodeT」はメイン クラス内の構造体であり、その構造体には構造体型の別のオブジェクトへのポインターが含まれています。'nodeTPtr' は単に 'ListNodeT' オブジェクトへのポインタであり、'headTrans' はタイプ ListNodeT のオブジェクト、特にリンクされたリストの最初のノードを指す (クラスに非公開で含まれる) ポインタです。
クラス "List" は、リンクされたリストを対象としています。
「DataList.h」ファイルは次のとおりです。
#ifndef DATALIST_H
#define DATALIST_H
#include <iostream>
#include <fstream>
#include <ostream>
#include <iomanip>
using namespace std;
const int MAXDISCIPLINES = 4;
const int MAXBREEDS = 4;
struct HORSE {
int ID;
string name; // maximum 25 alphanumeric characters, spaces included
double height;// in inches?
int age;
char genderCode;//'m', 'f', 'M', or 'F'
int breed;
int disciplineCount;
int discipline[MAXDISCIPLINES];
double lowBid; // minimum selling price
};
struct TRANS {
char transCode; //'A' for add, 'D' for delete or updating disciplines, or 'P' for updating lowBid price
HORSE transHorse;
};
class List {
private:
struct ListNodeT {
TRANS trans;
struct ListNodeT *nextLNT;
};
ListNodeT *headTrans;
struct ListNodeH {
HORSE horse;
struct ListNodeH *nextLNH;
};
ListNodeH *headHorse;
public:
//ListNodeH *headHorse;
//ListNodeT *headTrans;
List();
List(const List &obj);
~List();
bool InsertHorse(HORSE newHorse);
bool InsertTrans(TRANS newTrans);
bool DeleteHorse(int target);
bool DeleteTrans(int target);
bool ViewHorse(int target, HORSE &viewHorse);
bool ViewTrans(int target, TRANS &viewTrans);
int getNumHorses();
void getNumTrans(int &numA, int &numDel, int &numDisc, int &numP);
bool TransactOnce(int &skip, TRANS &thisTrans, string &failString);
bool UpdateDisc(TRANS thisTrans);
bool UpdatePrice(TRANS thisTrans);
void ReportOneTransaction(fstream &strm, TRANS thisTrans);
}; //end List class definition
//methods are in file DataList.cc and compiled separately.
#endif
以下は私の「DataList.cc」ファイルです。問題の「TransactOnce()」は下の方にあります。
#include "DataList.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <ostream>
#include <iomanip>
using namespace std;
//constructor
List::List(){
headHorse = NULL;
headTrans = NULL;
}
//copy constructor
List::List(const List &obj){
//copy the linked list of horses
ListNodeH *nodeHPtr;
ListNodeH **newListHPtr;
headHorse = NULL;
newListHPtr = &headHorse; //means &(this->headHorse), not &(obj.headHorse)
nodeHPtr = obj.headHorse;
while (nodeHPtr != NULL) {
*newListHPtr = new ListNodeH;
(*newListHPtr)->horse = nodeHPtr->horse;
(*newListHPtr)->nextLNH = NULL;
newListHPtr = &((*newListHPtr)->nextLNH);
nodeHPtr = nodeHPtr->nextLNH;
}
//copy the linked list of transactions
ListNodeT *nodeTPtr;
ListNodeT **newListTPtr;
headTrans = NULL;
newListTPtr = &headTrans;
nodeTPtr = obj.headTrans;
while (nodeTPtr != NULL) {
*newListTPtr = new ListNodeT;
(*newListTPtr)->trans = nodeTPtr->trans;
(*newListTPtr)->nextLNT = NULL;
newListTPtr = &((*newListTPtr)->nextLNT);
nodeTPtr = nodeTPtr->nextLNT;
}
}//end copy constructor
//destructor
List::~List(){
//destroy the list of horses
ListNodeH *nodeHPtr;
ListNodeH *nextHNode;
nodeHPtr = headHorse;
while(nodeHPtr != NULL){
nextHNode = nodeHPtr->nextLNH;
delete nodeHPtr;
nodeHPtr = nextHNode;
}//end walkthrough
//destroy the list of transactions
ListNodeT *nodeTPtr;
ListNodeT *nextTNode;
nodeTPtr = headTrans;
while(nodeTPtr != NULL){
nextTNode = nodeTPtr->nextLNT;
delete nodeTPtr;
nodeTPtr = nextTNode;
}//end walkthrough
}//end List::~List()
//********************************************************************
// FUNCTION NAME: InsertHorse()
// FUNCTION PURPOSE: inserts a new HORSE struct into our list
// INPUT PARAMETERS:
// 1. HORSE newHorse - the object of type DATA to be inserted into the List.
//RETURN VALUE – bool
//********************************************************************
bool List::InsertHorse(HORSE newHorse){
bool success = false;
ListNodeH *newNodeHPtr;
ListNodeH *nodeHPtr;
ListNodeH *prevNodeHPtr = NULL;
newNodeHPtr = new ListNodeH;
newNodeHPtr->horse = newHorse;
if(!headHorse){ //if head==NULL, our list is empty
headHorse = newNodeHPtr;
newNodeHPtr->nextLNH = NULL;
success = true;
}
else { //perhaps add? Our list is currently not empty.
nodeHPtr = headHorse;
//prevNodePtr; [sic] in my notes. I think it's supposed to be prevNodePtr = NULL;, but this should already be true
while(nodeHPtr != NULL && nodeHPtr->horse.ID < newHorse.ID){ //searches for approriate place
prevNodeHPtr = nodeHPtr;
nodeHPtr = nodeHPtr->nextLNH;
}
if(nodeHPtr != NULL && nodeHPtr->horse.ID == newHorse.ID){ //checks for duplicates
delete newNodeHPtr;
success = false; //note: this is the only way that Insert could return false
}
else { //insert the node
success = true;
newNodeHPtr->nextLNH = nodeHPtr;
if(prevNodeHPtr == NULL) //we're at the beginning of the list
headHorse = newNodeHPtr;
else //not at the beginning of the list
prevNodeHPtr->nextLNH = newNodeHPtr;
}//successful insertion
}
// delete newNodeHPtr;
return success;
}
//end List::InsertHorse()
//********************************************************************
// FUNCTION NAME: InsertTrans()
// FUNCTION PURPOSE: inserts a new TRANS struct into our list.
// if the transaction is trying to delete or update a horse that does not exist,
// returns false, and transaction is not inserted.
// INPUT PARAMETERS:
// 1. TRANS newTrans - the object of type TRANS to be inserted into the List.
//RETURN VALUE – bool
//********************************************************************
bool List::InsertTrans(TRANS newTrans){
bool success = false;
ListNodeT *newNodeTPtr;
ListNodeT *nodeTPtr;
ListNodeT *prevNodeTPtr = NULL;
newNodeTPtr = new ListNodeT;
newNodeTPtr->trans = newTrans;
HORSE dummyHorse; //dummy variable to be passed by reference to ViewHorse()
//we need to ensure a few things
//no duplicate IDs in transactions
//no Del, Disc, or P transactions for which the horse dosn't already exist in inventory
if(!headTrans){ //if head==NULL, our list is empty
headTrans = newNodeTPtr;
newNodeTPtr->nextLNT = NULL;
success = true;
}
else { //perhaps add? Our list is currently not empty.
nodeTPtr = headTrans;
//prevNodePtr; [sic] in my notes. I think it's supposed to be prevNodePtr = NULL;, but this should already be true
while(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID < newTrans.transHorse.ID){ //searches for approriate place
prevNodeTPtr = nodeTPtr;
nodeTPtr = nodeTPtr->nextLNT;
}
//check for duplicates
if(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID == newTrans.transHorse.ID){
delete newNodeTPtr;
success = false;
}
//in the case of Delete or Update transactions for which the horse does not already exist in inventory
else if((newTrans.transCode == 'D' || newTrans.transCode == 'P') && !List::ViewHorse(newTrans.transHorse.ID, dummyHorse)){
delete newNodeTPtr;
success = false;
}
else { //insert the transaction node
success = true;
newNodeTPtr->nextLNT = nodeTPtr;
if(prevNodeTPtr == NULL) //we're at the beginning of the list
headTrans = newNodeTPtr;
else //not at the beginning of the list
prevNodeTPtr->nextLNT = newNodeTPtr;
}//successful insertion
}
// delete newNodeTPtr;
return success;
}//end List::InsertTrans()
//********************************************************************
// FUNCTION NAME: DeleteHorse()
// FUNCTION PURPOSE: deletes a HORSE struct from our object of class List.
// INPUT PARAMETERS:
// 1. int target - the ID of the object of type HORSE to be deleted from List
//RETURN VALUE – bool
//********************************************************************
bool List::DeleteHorse(int target){
bool success = false;
ListNodeH *nodeHPtr;
ListNodeH *prevHPtr;
if (!headHorse) //empty list
success = false;
else if (headHorse->horse.ID == target) { //found target at the beginning of list, delete it
nodeHPtr = headHorse->nextLNH;
delete headHorse;
headHorse = nodeHPtr;
success=true;
}
else { // maybe delete?
nodeHPtr = headHorse;
while(nodeHPtr!=NULL && nodeHPtr->horse.ID < target){ //searching...
prevHPtr = nodeHPtr;
nodeHPtr = nodeHPtr->nextLNH;
}
if(nodeHPtr == NULL && nodeHPtr->horse.ID != target) //we're at the end of the list, and if target's not here...
success=false; //deletion failed. This is the only case where Delete() returns false.
else { //we're between the beginning and end, and we found the target
prevHPtr->nextLNH = nodeHPtr->nextLNH;
delete nodeHPtr; //delete target.
success = true;
}
}
return success;
}
//********************************************************************
// FUNCTION NAME: DeleteTrans()
// FUNCTION PURPOSE: deletes a TRANS struct from our object of class List.
// INPUT PARAMETERS:
// 1. int target - the ID of the object of type TRANS to be deleted from List
//RETURN VALUE – bool
//********************************************************************
bool List::DeleteTrans(int target){
bool success = false;
ListNodeT *nodeTPtr;
ListNodeT *prevTPtr;
if (!headTrans) //empty list
success = false;
else if (headTrans->trans.transHorse.ID == target) { //found target at the beginning of list, delete it
nodeTPtr = headTrans->nextLNT;
delete headTrans;
headTrans = nodeTPtr;
success=true;
}
else { // maybe delete?
nodeTPtr = headTrans;
while(nodeTPtr!=NULL && nodeTPtr->trans.transHorse.ID < target){ //searching...
prevTPtr = nodeTPtr;
nodeTPtr = nodeTPtr->nextLNT;
}
if(nodeTPtr == NULL && nodeTPtr->trans.transHorse.ID != target) //we're at the end of the list, and if target's not here...
success=false; //deletion failed. This is the only case where Delete() returns false.
else { //we're between the beginning and end, and we found the target
prevTPtr->nextLNT = nodeTPtr->nextLNT;
delete nodeTPtr; //delete target.
success = true;
}
}
return success;
}
//********************************************************************
// FUNCTION NAME: ViewHorse()
// FUNCTION PURPOSE: finds the HORSE struct whose ID is target, then returns the HORSE by reference.
// INPUT PARAMETERS:
// 1. int target - the ID to be searched for
// 2. HORSE &viewHorse - the object of type HORSE to be found and returned (by reference)
//RETURN VALUE – bool
//********************************************************************
//returns by reference the HORSE in the list with ID == target
//if View() returns false, then the target was not found and &viewHorse was not changed by ViewHorse().
bool List::ViewHorse(int target, HORSE &viewHorse){
bool success = false;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse; //start at the beginning of the list
while(nodeHPtr != NULL && nodeHPtr->horse.ID < target) //search...
nodeHPtr = nodeHPtr->nextLNH;
//which test failed?
if(nodeHPtr == NULL || nodeHPtr->horse.ID != target) //we're at the end of the list, or didn't find the target.
success = false; //Note: this is the ONLY way that ViewHorse() returns false.
else { //nodeHPtr != NULL && nodeHPtr->horse.ID == target, we found the target
success = true;
viewHorse = nodeHPtr->horse; //return by reference the HORSE in the list with ID == target
}
return success;
}//end List::ViewHorse()
//********************************************************************
// FUNCTION NAME: ViewTrans()
// FUNCTION PURPOSE: finds the TRANS struct whose ID is target, then returns the TRANS by reference.
// INPUT PARAMETERS:
// 1. int target - the ID to be searched for
// 2. TRANS &viewTrans - the object of type TRANS to be found and returned (by reference)
//RETURN VALUE – bool
//********************************************************************
//returns by reference the TRANS in the list with ID == target
//if ViewTrans() returns false, then the target was not found and &viewTrans was not changed by ViewTrans().
bool List::ViewTrans(int target, TRANS &viewTrans){
bool success = false;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans; //start at the beginning of the list
while(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID < target) //search...
nodeTPtr = nodeTPtr->nextLNT;
//which test failed?
if(nodeTPtr == NULL || nodeTPtr->trans.transHorse.ID != target) //we're at the end of the list, or didn't find the target.
success = false; //Note: this is the ONLY way that ViewTrans() returns false.
else { //nodeTPtr != NULL && nodeTPtr->horse.ID == target, we found the target
success = true;
viewTrans = nodeTPtr->trans; //return by reference the TRANS in the list with ID == target
}
return success;
}//end List::ViewTrans
//********************************************************************
// FUNCTION NAME: getNumHorses()
// FUNCTION PURPOSE: returns the number of nodes in our list of horses
// INPUT PARAMETERS: [none]
//RETURN VALUE – int
//********************************************************************
int List::getNumHorses(){
int horseCounter = 0;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse;
while(nodeHPtr != NULL){
nodeHPtr = nodeHPtr->nextLNH;
horseCounter++;
}
return horseCounter;
}//end List::getNumHorses()
//********************************************************************
// FUNCTION NAME: getNumTrans()
// FUNCTION PURPOSE: returns (by reference) the numbers of various types of transactions in our list of transactions
// INPUT PARAMETERS:
// 1.int &numA - number of "Add" transactions
// 2.int &numDel - number of "Delete" transactions
// 3.int &numDisc - number of "update discipline" transactions
// 4.int &numP - number of "update lowBid" transactions
//RETURN VALUE – void
//********************************************************************
void List::getNumTrans(int &numA, int &numDel, int &numDisc, int &numP){
numA = 0;
numDel = 0;
numDisc = 0;
numP = 0;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans;
while(nodeTPtr != NULL){
if(nodeTPtr->trans.transCode == 'A')
numA++;
else if(nodeTPtr->trans.transCode == 'D'){
if (nodeTPtr->trans.transHorse.disciplineCount == 0)
numDel++;
else
numDisc++;
}
else if(nodeTPtr->trans.transCode == 'P'){
numP++;
}
nodeTPtr = nodeTPtr->nextLNT;
}
}//end List::getNumTrans()
//********************************************************************
// FUNCTION NAME: TransactOnce()
// FUNCTION PURPOSE: Performs a single transaction.
// [skip] number of transactions at the beginning of the linked list of trans are skipped.
// The transaction immediately after the skipped transactions is attempted.
// If the transaction fails, skip is incremented and the function returns false.
// In any case, thisTrans is returned by reference as the transaction that was just attempted.
// INPUT PARAMETERS:
// 1. int &skip - the number of transactions to skip
// 2. TRANS &thisTrans - the returned transaction that was just attempted
// 3. string &failString - the ERROR, if any.
//RETURN VALUE – bool
//********************************************************************
bool TransactOnce(int &skip, TRANS &thisTrans, string &failString){
bool success = true;
stringstream failStream;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans;
HORSE dummyHorse; //for ViewHorse()
//if 'A', the ID must not already exist in our list of horses
//if 'D' or 'P', the horse must already exist in our list of horses.
//if 'D' and disciplineCount != 0, then
//the existing horse must already have disciplineCount <4
//transaction's transHorse.discipline[] must not have duplicates in the array
//each of transaction's transHorse.discipline[]s must be valid (1<= discipline <=4)
//find the transaction in question
for (int i=0; i < skip; i++){
nodeTPtr = nodeTPtr->nextLNT;
}
//nodeTPtr is now pointing to the appropriate ListNodeT.
if (nodeTPtr->trans.transCode == 'A' && !List::InsertHorse(nodeTPtr->trans.transHorse)){
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via InsertHorse().";
success = false;
}
else if (nodeTPtr->trans.transCode == 'D'){ //delete or update disciplines
if(nodeTPtr->trans.transHorse.disciplineCount == 0 && !List::DeleteHorse(nodeTPtr->trans.transHorse.ID)){ //for deletion
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via DeleteHorse().";
success = false;
}
else if(nodeTPtr->trans.transHorse.disciplineCount != 0 && !List::UpdateDisc(nodeTPtr->trans)){ //update disciplines
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via UpdateDisc().";
success = false;
}
}
else if (nodeTPtr->trans.transCode == 'P' && !List::UpdatePrice(nodeTPtr->trans)){
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via UpdatePrice().";
success = false;
}
else {
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << ", not a valid transCode.";
success = false;
}
if (success){ //attempt to delete the transaction
if (!List::DeleteTrans(nodeTPtr->trans.transHorse.ID)){
failStream << "ERROR, could not delete transaction " << nodeTPtr->trans.transHorse.ID << ".";
success = false;
}
else //return true and error free
failStream << "No error to report.";
}
if (!success)
skip++;
failStream << "\n";
failString = failStream.str();
return success;
}//end TransactOnce()
//********************************************************************
// FUNCTION NAME: UpdateDisc()
// FUNCTION PURPOSE: for an "update discipline" transaction, update the disciplines of that horse in inventory.
// INPUT PARAMETERS:
// 1. TRANS thisTrans - the transaction to be executed
//RETURN VALUE – bool
//********************************************************************
bool List::UpdateDisc(TRANS thisTrans){
bool success = true;
ListNodeH *nodeHPtr = headHorse; //no need for a ListNodeT
//obtain a pointer to the horse in question
while (nodeHPtr != NULL && nodeHPtr->horse.ID < thisTrans.transHorse.ID)
nodeHPtr = nodeHPtr->nextLNH;
if(nodeHPtr == NULL) //failed to find the horse
success = false;
//horse found; nodeHPtr->horse.ID == thisTrans.transHorse.ID
else if(thisTrans.transCode != 'D') //this isn't even a "D" transaction...
success = false;
else if(thisTrans.transHorse.disciplineCount == 0) //nothing to do, this is for deletion
success = false;
else if(nodeHPtr->horse.disciplineCount + thisTrans.transHorse.disciplineCount > 4)
success = false; //too many disciplines
else {
//update the disciplines
while(thisTrans.transHorse.disciplineCount !=0){
nodeHPtr->horse.discipline[nodeHPtr->horse.disciplineCount] = thisTrans.transHorse.discipline[thisTrans.transHorse.disciplineCount-1];
nodeHPtr->horse.disciplineCount++;
thisTrans.transHorse.disciplineCount--;
}//disciplines are now updated but perhaps not sorted
//bubble-sort the horse's array of disciplines.
int i, j;
bool swaped = true;
int tempInt;
for(i = 1; (i <= nodeHPtr->horse.disciplineCount)&&swaped; i++){
swaped = false;
for (j=0; j< nodeHPtr->horse.disciplineCount-1; j++){
if(nodeHPtr->horse.discipline[j] > nodeHPtr->horse.discipline[j+1]){
tempInt = nodeHPtr->horse.discipline[j];
nodeHPtr->horse.discipline[j] = nodeHPtr->horse.discipline[j+1];
nodeHPtr->horse.discipline[j+1] = tempInt;
swaped = true;
}
}
}
}//end update and sort horse's disciplines
return success;
}//end List::UpdateDisc()
//********************************************************************
// FUNCTION NAME: UpdatePrice()
// FUNCTION PURPOSE: for an "update lowBid" transaction, update the lowBid of that horse in inventory.
// INPUT PARAMETERS:
// 1. TRANS thisTrans - the transaction to be executed
//RETURN VALUE – bool
//********************************************************************
bool List::UpdatePrice(TRANS thisTrans){
bool success = true;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse;
//obtain a pointer to the horse in question
while (nodeHPtr != NULL && nodeHPtr->horse.ID < thisTrans.transHorse.ID)
nodeHPtr = nodeHPtr->nextLNH;
if(nodeHPtr == NULL) //failed to find the horse
success = false;
//else, horse found; nodeHPtr->horse.ID == thisTrans.transHorse.ID
else if(thisTrans.transCode != 'P') //this isn't even a "P" transaction...
success = false;
else { //update lowBid
nodeHPtr->horse.lowBid = thisTrans.transHorse.lowBid;
}
return success;
}//end List::UpdatePrice()
//********************************************************************
// FUNCTION NAME: ReportOneTransaction()
// FUNCTION PURPOSE: prints to Report.out a single transaction. called by Transact().
// INPUT PARAMETERS:
// 1. fstream &strm - the stream to print to.
// 2. TRANS oneTrans - the transaction being reported.
//RETURN VALUE – void
//********************************************************************
void List::ReportOneTransaction(fstream &strm, TRANS oneTrans){
//some "Ragged Arrays"
string breedDescription[MAXBREEDS+1] = {"Dummy", "Pleasure Saddle Horse", "American Fox Trotter", "Virginia Highlander", "Arabian"};//21
string disciplineDescription[MAXDISCIPLINES+1] = {"Dummy", "Dressage", "Jumper", "Hunter", "Western Pleasure"};//16
if (oneTrans.transCode == 'A')
strm << "Horse ADDED to inventory named '" ;
else
strm << "Horse REMOVED from inventory named '" ;
strm << oneTrans.transHorse.name << "'"<< endl;
strm << "______________________________________________________________________\n";//70
strm <<"ID Height Age M/F LowBid "<< oneTrans.transHorse.disciplineCount << " Discipline(s): Breed\n";
strm << left << setw(3) <<oneTrans.transHorse.ID <<" ";//ID
strm << left << setw(5) <<setprecision(2) <<oneTrans.transHorse.height <<" ";//height (double)
strm << left << setw(3) <<oneTrans.transHorse.age <<" ";//age
strm << left << setw(1) <<oneTrans.transHorse.genderCode; //genderCode (char)
strm << " "<<left<<'$';
strm << right << fixed << setw(8) << setprecision(2) << oneTrans.transHorse.lowBid ;//lowBid (double)
strm << left << " " << setw(16) << disciplineDescription[oneTrans.transHorse.discipline[0]] ;
strm << " " << breedDescription[oneTrans.transHorse.breed] << endl;
for (int j=1; j < oneTrans.transHorse.disciplineCount; j++){
strm << " ";
strm << disciplineDescription[oneTrans.transHorse.discipline[j]] << endl;
}
strm << endl << endl;
}//end ReportOneTransaction()