pvd
pvd

Reputation: 1343

error on include the fstream.h header

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();
}

Upvotes: 1

Views: 7361

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 755104

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:

#!/bin/sh
# Check whether headers compile

tmp=chkhdr-$$
trap 'rm -f $tmp.?; exit 1' 0 1 2 3  13 15

cat > $tmp.c <<EOF
#include HEADER /* Check self-containment */
#include HEADER /* Check idempotence */
int main(void) { return 0; }
EOF

options=
for file in "$@"
do
    case "$file" in
    (-*) options="$options $file";;
    (*)  echo "$file"
         ${CC:-gcc} $options -DHEADER="\"$file\"" -c $tmp.c
         ;;
    esac
done

rm -f $tmp.?
trap 0

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.h header was not idempotent; I immediately added the standard stanzas at top and bottom:

#ifndef STUDENT_H_INCLUDED
#define STUDENT_H_INCLUDED

...original contents of student.h...

#endif /* STUDENT_H_INCLUDED */

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.h header alone was:

In file included from chkhdr-8120.c:1:
/usr/include/c++/4.2.1/bits/ios_base.h: In copy constructor ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:
/usr/include/c++/4.2.1/bits/ios_base.h:779: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.2.1/iosfwd:55: error: within this context
/usr/include/c++/4.2.1/iosfwd: In copy constructor ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’:
/usr/include/c++/4.2.1/iosfwd:64: note: synthesized method ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’ first required here 
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:20: note: synthesized method ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’ first required here 
student.h:20: error:   initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’

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.h to read:

    ostream& writeLegibly(ostream&);

resolved that problem, and the student.h header compiled cleanly. The other headers were also clean. Then it was a simple matter to compile the source files. Only student.cpp had an issue:

student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34: error: ‘cout’ was not declared in this scope

It sounds like a case of 'should use std::cout instead', but adding that leads to:

student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34: error: ‘cout’ is not a member of ‘std’

That is fixed by including #include <iostream>. Then the code compiles cleanly under:

g++ -c *.cpp

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:

  1. Ensure headers work cleanly on their own (chkhdr).
  2. Tackle one file at a time.
  3. Problem minimization.

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.

Upvotes: 4

ervinbosenbacher
ervinbosenbacher

Reputation: 1780

While the compiler have changed C++ and C are backwards compatible. One of the strengths of the language. Anyway I have copied out your code into a VS2010 because it was easier for me to analyse the issues with it.

  1. put the #include < iostream > in your personal.h. It is used by personal.cpp where you have a cout.

  2. The signature in student.h of

    ostream& writeLegibly(ostream);
    

    is wrong, it should be:

    ostream& writeLegibly(ostream&);
    
  3. I have moved the implementation code in database.cpp into the database.h. Plain simple cut and paste above the #endif. Due to the template nature the compiler did not like it that it was in a separate implementation cpp.

Hope that helps.

Upvotes: 3

Troubadour
Troubadour

Reputation: 13431

In Student change

ostream& writeLegibly(ostream);

to

ostream& writeLegibly(ostream&);

and that should fix a lot. By missing the ampersand you were trying to copy the stream.

Upvotes: 3

CapelliC
CapelliC

Reputation: 60034

the errors report

student.cpp:34:5: error: ‘cout’ was not declared in this scope

I think you need

#include <iostream>

Upvotes: 3

Related Questions