-
new coder using Dev C++
Fist Part
I am trying to work on a simple database project which needs to determine if a record is null. I am wanting to do this by using the function isNull() in the classes Personal and Student to determine that a record is null. Then overwrite the record to be deleted by a null record. A null record can be defined as having nonnumeric characters (a tombstone) in the first position of the SSN member.
Second Part
Then I would like to define the function remove() in the Database which should locate the position of a record to be deleted and overwrite it with a null record. Then after a session is finshed. I would like to invoke a database destructor which copies the nonnull records to a new data file, deletes the old data file, and renames the new data file with the name of the old data file.
Here is what I have so far... Any help with code, advice, or tips would be greatly appreciated...
Code:
************************ personal.h *********************
public:
Personal();
Personal(char*,char*,char*,int,long);
void writeToFile(fstream&) const;
void readFromFile(fstream&);
void readKey();
int size() const {
return 9 + nameLen + cityLen + sizeof(year) + sizeof(salary);
}
bool operator==(const Personal& pr) const {
return strcmp(pr.SSN,SSN) == 0;
}
protected:
const int nameLen, cityLen;
char SSN[10], *name, *city;
int year;
long salary;
ostream& writeLegibly(ostream&);
friend ostream& operator<<(ostream& out, Personal& pr) {
return pr.writeLegibly(out);
}
istream& readFromConsole(istream&);
friend istream& operator>>(istream& in, Personal& pr) {
return pr.readFromConsole(in);
}
};
#endif
****************** personal.cpp *******************
#include
#include "personal.h"
Personal::Personal() : nameLen(10), cityLen(10) {
name = new char[nameLen+1];
city = new char[cityLen+1];
}
Personal::Personal(char ........n, char *n, char *c, int y, long s) :
nameLen(10), cityLen(10) {
name = new char[nameLen+1];
city = new char[cityLen+1];
strcpy(SSN,ssn);
strcpy(name,n);
strcpy(city,c);
year = y;
salary = s;
}
void Personal::writeToFile(fstream& out) const {
out.write(SSN,9);
out.write(name,nameLen);
out.write(city,cityLen);
out.write(reinterpret_cast(&year),sizeof(int));
out.write(reinterpret_cast(&salary),sizeof(int));
}
void Personal::readFromFile(fstream& in) {
in.read(SSN,9);
in.read(name,nameLen);
in.read(city,cityLen);
in.read(reinterpret_cast(&year),sizeof(int));
in.read(reinterpret_cast(&salary),sizeof(int));
}
void Personal::readKey() {
char s[80];
cout << "Enter SSN: ";
cin.getline(s,80);
strncpy(SSN,s,9);
}
ostream& Personal::writeLegibly(ostream& out) {
SSN[9] = name[nameLen] = city[cityLen] = '\0';
out << "SSN = " << SSN << ", name = " << name
<< ", city = " << city << ", year = " << year
<< ", salary = " << salary;
return out;
}
istream& Personal::readFromConsole(istream& in) {
char s[80];
cout << "SSN: ";
in.getline(s,80);
strncpy(SSN,s,9);
cout<<'['<<SSN<<']';
cout << "Name: ";
in.getline(s,80);
strncpy(name,s,nameLen);
cout<<'['<<name<<']';
cout << "City: ";
in.getline(s,80);
strncpy(city,s,cityLen);
cout<<'['<<city<<']';
cout << "Birthyear: ";
in >> year;
cout<<'['<<year<<']';
cout << "Salary: ";
in >> salary;
cout<<'['<<salary<<']';
cin.ignore();
return in;
}
**************************** student.h *********************
#ifndef STUDENT
#define STUDENT
#include "personal.h"
class Student : public Personal {
public:
Student();
Student(char*,char*,char*,int,long,char*);
void writeToFile(fstream&) const;
void readFromFile(fstream&);
int size() const {
return Personal::size() + majorLen;
}
protected:
char *major;
const int majorLen;
ostream& writeLegibly(ostream&);
friend ostream& operator<<(ostream& out, Student& sr) {
return sr.writeLegibly(out);
}
istream& readFromConsole(istream&);
friend istream& operator>>(istream& in, Student& sr) {
return sr.readFromConsole(in);
}
};
#endif
******************************** student.cpp ********************
#include
#include "student.h"
Student::Student() : majorLen(10) {
Personal();
major = new char[majorLen+1];
}
Student::Student(char ........n, char *n, char *c, int y, long s, char *m) :
majorLen(11) {
Personal(ssn,n,c,y,s);
major = new char[majorLen+1];
strcpy(major,m);
}
void Student::writeToFile(fstream& out) const {
Personal::writeToFile(out);
out.write(major,majorLen);
}
void Student::readFromFile(fstream& in) {
Personal::readFromFile(in);
in.read(major,majorLen);
}
ostream& Student::writeLegibly(ostream& out) {
Personal::writeLegibly(out);
major[majorLen] = '\0';
out << ", major = " << major;
return out;
}
istream& Student::readFromConsole(istream& in) {
Personal::readFromConsole(in);
char s[80];
cout << "Major: ";
in.getline(s,80);
strncpy(major,s,9);
return in;
}
***************************** database.h ************************
#ifndef DATABASE
#define DATABASE
template
class Database {
public:
Database();
void run();
private:
fstream database;
char fName[20];
ostream& print(ostream&);
void add(T&);
bool find(const T&);
void modify(const T&);
friend ostream& operator<<(ostream& out, Database& db) {
return db.print(out);
}
};
#endif
*********************** database.cpp *************************
#include
#include "personal.h"
#include "student.h"
#include "database.h"
template
Database::Database() {
}
template
void Database::add(T& d) {
database.open(fName,ios::in|ios::out|ios::binary);
database.seekp(0,ios::end);
d.writeToFile(database);
database.close();
}
template
void Database::modify(const T& d) {
T tmp;
database.open(fName,ios::in|ios::out|ios::binary);
while (!database.eof()) {
tmp.readFromFile(database);
if (tmp == d) { // overloaded ==
cin >> tmp; // overloaded >>
database.seekp(-d.size(),ios::cur);
tmp.writeToFile(database);
database.close();
return;
}
}
database.close();
cout << "The record to be modified is not in the database\n";
}
template
bool Database::find(const T& d) {
T tmp;
database.open(fName,ios::in|ios::binary);
while (!database.eof()) {
tmp.readFromFile(database);
if (tmp == d) { // overloaded ==
database.close();
return true;
}
}
database.close();
return false;
}
template
ostream& Database::print(ostream& out) {
T tmp;
database.open(fName,ios::in|ios::binary);
while (true) {
tmp.readFromFile(database);
if (database.eof())
break;
out << tmp << endl; // overloaded <<
}
database.close();
return out;
}
template
void Database::run() {
cout << "File name: ";
cin >> fName;
cin.ignore(); // skip '\n';
database.open(fName,ios::in);
if (database.fail())
database.open(fName,ios::out);
database.close();
char option[5];
T rec;
cout << "1. Add 2. Find 3. Modify a record; 4. Exit\n";
cout << "Enter an option: ";
while (cin.getline(option,5)) {
cout<<'['<<option<<']';
if (*option == '1') {
cin >> rec; // overloaded >>
add(rec);
}
else if (*option == '2') {
rec.readKey();
cout << "The record is ";
if (find(rec) == false)
cout << "not ";
cout << "in the database\n";
}
else if (*option == '3') {
rec.readKey();
modify(rec);
}
else if (*option != '4')
cout << "Wrong option\n";
else return;
cout << *this; // overloaded <<
cout << "Enter an option: ";
}
}
int main() {
Database().run();
// Database().run();
return 0;
}
-
[code][/code] too hard to read without indentation.
-
In main, I think you might need an actual Database object.
Code:
int main() {
Database myDataBase;
myDataBase.run();
return 0;
}
As for the rest, using STL strings and containers usually makes things easier...
-
Many things are way off. For example, you use template instead of template <typename T> or template <class T>. Also, you define templated classes and functions inside an implementation file (.cpp) which is illegal. Templated classes/structs/functions should be declared and implemented in a header file. I think it's valid to have two separate header files though. You could have my_templated_class_header.h and my_templated_class_impl.h and then include my_templated_class_impl.h in my_templated_class_header.h. There's also a definite lack of indentation and comments which makes your code harder to read. Also, while we're there, you use dynamic memory allocation and C-string functions over std::string which is quite pointless. std::string will make you save a lot of time and hassle.