I am reading a book “Data Structures and Algorithms in C++” which was published at 2001, I think the c++ compiler should be changed a lot since that time, because I found the code in the book can not be compiled.
#include <fstream.h>
#include <string.h>
So I Google for the answer, and changed the code to
#include <fstream>
#include <cstring>
using namespace std;
But when I tried to compile the code, well, I got some error I have not ever seen:
oo@oo:~/raf$ g++ database.cpp personal.cpp student.cpp useDatabase.cpp -o useDatabase
In file included from /usr/include/c++/4.6/ios:45:0,
from /usr/include/c++/4.6/istream:40,
from /usr/include/c++/4.6/fstream:40,
from personal.h:4,
from student.h:1,
from student.cpp:1:
/usr/include/c++/4.6/bits/ios_base.h: In copy constructor ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’:
/usr/include/c++/4.6/bits/ios_base.h:788:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from /usr/include/c++/4.6/istream:41:0,
from /usr/include/c++/4.6/fstream:40,
from personal.h:4,
from student.h:1,
from student.cpp:1:
/usr/include/c++/4.6/ostream: In copy constructor ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’:
/usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ first required here
In file included from student.cpp:1:0:
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:17:39: note: synthesized method ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’ first required here
student.h:15:18: error: initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’
student.cpp: At global scope:
student.cpp:24:10: error: prototype for ‘std::ostream& Student::writeLegibly(std::ostream&)’ does not match any in class ‘Student’
student.h:15:18: error: candidate is: std::ostream& Student::writeLegibly(std::ostream)
student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34:5: error: ‘cout’ was not declared in this scope
In file included from /usr/include/c++/4.6/ios:45:0,
from /usr/include/c++/4.6/ostream:40,
from /usr/include/c++/4.6/iostream:40,
from useDatabase.cpp:1:
/usr/include/c++/4.6/bits/ios_base.h: In copy constructor ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’:
/usr/include/c++/4.6/bits/ios_base.h:788:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from /usr/include/c++/4.6/iostream:40:0,
from useDatabase.cpp:1:
/usr/include/c++/4.6/ostream: In copy constructor ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’:
/usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ first required here
In file included from useDatabase.cpp:2:0:
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:17:39: note: synthesized method ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’ first required here
student.h:15:18: error: initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’
oo@oo:~/raf$
I spent a lot of time to Google for the answer, but got even more error. Maybe I should register a Github account and upload my code there.
database.cpp
#include "database.h"
template<class T> Database<T>::Database() {
cout << "File name: ";
cin >> fName;
}
template<class T> void Database<T>::add(T& d){
database.open(fName, ios::in|ios::out|ios::binary);
database.seekp(0, ios::end);
d.writeToFile(database);
database.close();
}
template<class T> void Database<T>::modify(const T& d){
T tmp;
database.open(fName, ios::in|ios::out|ios::binary);
while(!database.eof()){
tmp.readFromFile(database);
if (tmp == d){
cin >> tmp;
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<class T> bool Database<T>::find(const T& d){
T tmp;
database.open(fName, ios::in|ios::binary);
while(!database.eof()){
tmp.readFromFile(database);
if (tmp == d){
database.close();
return true;
}
}
database.close();
return false;
}
template<class T> ostream& Database<T>::print(ostream& out){
T tmp;
database.open(fName, ios::in|ios::binary);
while(1){
tmp.readFromFile(database);
if (database.eof())
break;
out << tmp << endl;
}
database.close();
return out;
}
template<class T> void Database<T>::run() {
char option[5];
T rec;
cout << "1.Add 2.Find 3.Modify a record 4.Exit\n";
cout << "Enter an option: ";
cin.getline(option, 4);
while (cin.getline(option, 4)){
if (*option == '1'){
cin >> rec;
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;
cout << "Enter an option";
}
}
database.h
#ifndef DATABASE
#define DATABASE
#include <fstream>
#include <iostream>
using namespace std;
template<class T> 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
personal.cpp
#include "personal.h"
#include <iostream>
Personal::Personal() : nameLen(10), cityLen(10) {
name = new char[nameLen + 1];
city = new char[cityLen + 1];
}
Personal::Personal(char *ssn, 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<const char*>(&year), sizeof(int));
out.write(reinterpret_cast<const char*>(&salary), sizeof(int));
}
void Personal::readFromFile(fstream& in) {
in.read(SSN, 9);
in.read(name, nameLen);
in.read(city, cityLen);
in.read(reinterpret_cast<char *>(&year), sizeof(int));
in.read(reinterpret_cast<char *>(&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 << "Name: ";
in.getline(s, 80);
strncpy(name, s, nameLen);
cout << "City: ";
in.getline(s, 80);
strncpy(city, s, cityLen);
cout << "Birthyear: ";
in >> year;
cout << "Salary: ";
in >> salary;
in.getline(s, 80); //get '\n'
return in;
}
personal.h
#ifndef PERSONAL
#define PERSONAL
#include <fstream>
#include <cstring>
using namespace std;
class Personal {
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
student.cpp
#include "student.h"
Student::Student() : majorLen(10) {
Personal();
major = new char[majorLen + 1];
}
Student::Student(char *ssn, 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;
}
student.h
#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);
}
};
useDatabase.cpp
#include <iostream>
#include "student.h"
#include "personal.h"
#include "database.h"
int main(){
Database<Personal> db;
db.run();
}
This was a big — arguably too big — set of files to be analyzed in an SO question. You need to learn some methods of reducing the size of your problem for presentation to SO (or to Tech Support).
One of the first steps in C or C++ is to ensure that the headers you create compile cleanly. If the headers aren’t clean, you won’t be able to compile the code that uses the headers, so headers must be sorted out first.
To help me, I have a script that I call
chkhdr:I use it to check that headers are both self-contained and idempotent. A self-contained header can be included without any other headers before it, and it compiles. That means it can be used anywhere its services are needed without further ado. An idempotent header can be included multiple times without causing trouble. (I mainly work in C, hence the default compiler is GCC rather than G++. But I can set
CC=g++in the environment to switch to C++ work.)Your
student.hheader was not idempotent; I immediately added the standard stanzas at top and bottom:The detailed choice of guard macro name is up to you; that’s the naming scheme I use these days, but there’s some merit in using something like an MD5 checksum of an draft of the header to give you a quasi-random guard macro.
The output from compiling the
student.hheader alone was:The last line of the error message points firmly at the issue; the other messages are somewhat tangential, and lead up to the crux message. (Very often, especially in C, the first error is the most significant. It was surprising to me that the last line was the key one.) Changing line 20 of
student.hto read:resolved that problem, and the
student.hheader compiled cleanly. The other headers were also clean. Then it was a simple matter to compile the source files. Onlystudent.cpphad an issue:It sounds like a case of ‘should use
std::coutinstead’, but adding that leads to:That is fixed by including
#include <iostream>. Then the code compiles cleanly under:I can’t link; I run into undefined references to the Database code, but that’s not surprising.
Summary
The details of the fixes are not incredibly important. What is important is the techniques. The key techniques here are:
chkhdr).We should not have had to deal with all the code; you should have been able to isolate the problems much better. This is an important skill in any situation where you’re reporting software problems to others. Eliminate the extraneous, and reduce to bare essentials.