From: lih@ucunix.san.uc.edu (hongbo li)
Subject: c++ template
Organization: University of Cincinnati
Distribution: usa
Date: Wed, 29 Jul 92 00:44:43 GMT

// Hi, Everybody, I have one problem when I compiled the following  program,
// if someone can help me to fix it, I will very appreciate it.
// The compiler I used is GNU g++  

// problem.c
#include<iostream.h>
#include<iomanip.h>
#include<stdio.h>
#include<stream.h>
#include<string.h>
#include<strings.h>
#include<stdarg.h>
#include<errno.h>
#include<libc.h>

enum access_mode { f_create, f_update };

class recfile{
protected:

    FILE* fp;
    char* name;
    int recsize;
    long curr_rec;
    int opened;
public:
    recfile(int recsize=1);
    virtual ~recfile(void) { close() ; cout<<"virtual destructor\n";}
    virtual int open(char* fname, enum access_mode mode);
    virtual int close(void);
    int isopen(void) { return opened; }
    long seek(long recno, int seek_mode=SEEK_SET);
    long rw(int dir, void* data, unsigned nrecs, long recno);
    virtual void err_handler(int errtype, ...);
};


recfile::recfile(int rs)
{
  name = NULL;
  fp = NULL;
  recsize = rs;
  opened = 0;
}

int recfile::open(char* fname, enum access_mode mode)
{
close();
 if ( mode == f_create) 
 {
  fp = fopen(fname, "w+b");
  cout<<"open file successful\n";
  opened=1;
}
else
 {
     fp = fopen(fname, "r");
     if ( fp != NULL )
                       {
                         fclose(fp);
                         fp = fopen(fname, "r+b");
                        }
  }
if ( fp == NULL ) 
     {
       cout<<"enter err2\n";    
       err_handler(2, fname);
          opened = 0;
     }
else {
          name= new char[strlen(fname) + 1 ];
          strcpy( name, fname);
          opened =1 ;
      }
return opened;
}


int recfile::close(void)
{
 if ( opened ) 
 {
   if ( fclose(fp) == 0 )
   {
     opened = 0;
     delete[] name;
   }
   else  err_handler(3) ; 
 }
 return !opened;
}


long recfile::seek(long recno, int seek_mode)
{
  long newpos= recno * recsize ;
 if ( opened ) 
  {
 int s;
 

  if (  s = fseek(fp, newpos, seek_mode)  )
      {
        err_handler(4, recno ) ;
        return -1;
      }
    
     curr_rec = newpos / recsize;
    return curr_rec ;
}
err_handler(1);
  return -1;
}



long recfile::rw(int dir, void* d, unsigned nr, long recno)
{
  long recsmoved=0;
  if ( opened )
  {
  
     if ( recno == -1 )
     {
          if ( seek (0L, SEEK_CUR) == -1 )    return 0;
     }
     else 
     {
          if ( seek(recno, SEEK_SET) == -1 ) return 0;
     }
 
     if ( dir == 1 )
                    { recsmoved = fwrite(d, recsize, nr, fp );
                      cout<<"successful fwrite"<<recsmoved<<"\n"; 
                    }
     else 
         { recsmoved = fread(d, recsize, nr, fp);
           cout<<"recsmoved = "<<recsmoved<<"\n";
         } 
     if ( recsmoved != nr ) 
                {
                  cout<<"Enter err 5\n";
                  err_handler(5, dir, recno);
                } 
    return recsmoved;
   }
   else {
          err_handler(1);
          recsmoved=0;
        } 
return recsmoved;
}



char* dirnames[2] = { "read", "write" };
void recfile::err_handler(int errtype, ... )
{
  va_list arg_ptr;
  int dir;
  long rec;
  char* s;

  va_start(arg_ptr, errtype);
  switch ( errtype ) {
   case 0: 
           cout<<"No errori\n"; break;
   case 1:
           cout<<"trying to access unopened file\n";break;
   case 2: 
           cout<<"error 2 "<<"\n"; break;
   case 3: 
           cout<<"error 3 "<<name<<"\n"; break;
   case 4:  
           cout<<"error 4 "<<"\n";break;
   case 5:
           cout<<"error 5 \n"; break;
  }
  va_end(arg_ptr);
}


class part{

protected:

int partno;
int qty;
float price;

public:

  friend ostream& operator<<(ostream& strm, part& p);
  int same_key( part& b);
  void set(int p, int q,  float c){ 
    partno=p, qty=q, price=c;}

  void copy(part& p) { set(p.partno, p.qty, p.price);}
  part(void) { set(-1, 0,0); }
  part(part& p) { copy(p); }
  part(int p, int q, float c) { set(p,q,c); }
  void operator=(part &p) { copy(p); }
  int isnull() { return partno == -1; }
  int get_key(void) { return get_partno(); }
  int get_partno(void);
  int get_qty(void);
  int get_price(void);
  void input(void);
};


void skip_to_eol(istream& s)
{
  char c;
  s.clear();
  while(s.get(c) && c != '\n');
}

ostream& operator<<(ostream& strm, part& p)
{
   if ( p.isnull() ) return strm << "Null part";
   strm<<"partno: "<< p.partno<<" ";
   strm<<"qty:    "<< p.qty<<"   ";
   strm<<"price:    "<< p.price;
   return strm;
}

int part::same_key( part& b)
{
  return this->partno==b.partno;
}

int part::get_partno(void)
{
  cout<<"partno: ";
  if ( cin>>partno ) return 1;
  return 0;
} 

int part::get_qty(void)
{
  cout<<"qty: ";
  if ( cin>>qty ) return 1;
  return 0;
} 

int part::get_price(void)
{
  cout<<"price: ";
  if ( cin>>price ) return 1;
  return 0;
}
void part::input(void)
{
  while (1)
  {
       if ( get_partno() )
       {
             if ( isnull() ) break;
             if ( get_qty() ) 
             {
                 if ( get_price() ) break;
             }
        }
       cout<<"Invalid input, repress return--- try again:\n";
       skip_to_eol(cin);
   }
}



template<class T>
class file_of: public recfile{
public:
   file_of(void) : (sizeof(T)) {}

   long read(T& data, long recno= -1)
   {
       return rw(0, &data, 1, recno);
   }
  
   long write(T& data, long recno= -1)
   {
       return rw(1, &data, 1, recno);
   }
};


template<class T>
class db:   public file_of<T>
{
protected:
    unsigned nrecs;
    unsigned nitems;

public:
    db(void): nrecs(0), nitems(0) {}
    void update_header(void);
    void read_header(void);
    int open(char* fname, enum access_mode mode);
    int close(void);
    unsigned search(T& p);
    unsigned add(T& p);
   unsigned del(T& p, unsigned recno=0);
   unsigned update(T& p, unsigned recno=0);
    void list(ostream& strm);
};

template<class T>
void db<T>::read_header(void)
{
   T p;
   cout<<"Enter read_header() \n";
   read( p, 0);
   cout<<" finish read_header()\n"; 
   memcpy(&nrecs, &p, 4);
   memcpy(&nitems,((char*)&p)+4, 4);
   cout<<"nrecs= "<<nrecs<<"nitems= "<<nitems<<"\n";

}


template<class T>
void db<T>::update_header(void)
{
   T p;
          
   memcpy(&p, &nrecs, 4);
   memcpy(((char*)&p)+4, &nitems, 4);
   write(p, 0);
}


template<class T>
int db<T>::open(char* fname, enum access_mode mode)
{

  cout<<"fname= "<<fname<<endl;
  cout<<"mode= "<<mode<<endl;
  recfile::open(fname, mode);
  cout<<" db::open opened= "<<opened<<"\n";
  if ( opened && mode == f_update )
          read_header();
  return opened;
}

template<class T>
int db<T>::close(void)
{
   if ( opened ) update_header();
   return recfile::close();
}

template<class T>
unsigned db<T>::search(T& p)
{
   unsigned r;
   T q;
   for ( r =1; r<= nrecs; r++ )
   {
        if ( read(q,r) && q.same_key(p) )
        {
              p=q;
              return r;
        }
    }
    return 0;
 }

template<class T>
unsigned db<T>::add(T& p)
{
  unsigned r;
  T q;
  r = search(q);
  if ( r ) 
  {
    if ( write(p,r) )
    {
      nitems++;
      update_header();
      return r;
    }
  }
 else
 {
    if ( write(p, nrecs+1) )
    {
      nrecs++; nitems++;
      update_header();
      return nrecs;
    }
  }
  return 0;
}



template<class T>
unsigned db<T>::del(T& p, unsigned recno)
{
  unsigned r;
  if ( recno ) r = recno;
  else r = search(p);
 if ( r )
 {
    T q;
    write(q,r);
    nitems--;
    update_header();
   }
  return r;
}

template<class T>
unsigned db<T>::update(T& p, unsigned recno)
{
   unsigned r;
   if ( recno) r = recno;
   else r= search(p);
   if ( r ) 
   {
        write(p, r);
   }
   return r;
}




template<class T>
void db<T>::list(ostream& strm)
{
  int cur_rec, recs_seen;
  T p;
  
  for ( cur_rec = 1, recs_seen = 0;
        cur_rec <= nrecs && recs_seen < nitems;
        cur_rec++)
  {
    read(p, cur_rec);
    if ( !p.isnull() )
    {
      strm<<p<<"\n";
      recs_seen++;
    }
   }
}



// test driver
void menu(void)
{
   cout<<"\ndatabase service : \n\n";
   cout<<" c  Create database\n";
   cout<<" o  Open existing database\n";
   cout<<" f  Find part\n";
   cout<<" u  Update part\n";
   cout<<" a  Add part\n";
   cout<<" d  Delete part\n";
   cout<<" l  List parts\n";
   cout<<" q  Quit\n";
   cout<<" h  Help\n\n";
}


int get_action(void)
{
    char action;
    cout<<" > ";
    cin.clear();
    cin>>action;
    cout<<" action: "<<action<<"\n";
    return action;
}

int do_action(db<part>& f, int act)
{
   part p;
   char c, fname[80];
   unsigned rec;

   if ( act != 'q' && act != 'c' && act != 'o' &&
        act != 'h' && !f.isopen() )
   {
      cout<< "Database not opened\n";
      return act;
   }
   
  switch(act){
    case 'q':  cout<<"Closing down database ...\n";
               f.close();
               break;
    case 'c':  cout<<"Enter file name: ";
               cin.get(c);
               cin.get(fname, 80);
               cout<<" c : fname= "<<fname<<endl; 
               f.open(fname, f_create);
               break; 

    case 'o':  cout<<"Enter file name: ";
               cin.get(c);
               cin.get(fname, 80);
               f.open(fname, f_update);
               break; 
    case 'f':  cout<<"find ";
               if ( p.get_key())
               {
                   if ( ( rec = f.search(p) ) !=0 )
                   {
                       cout<<"Part found at rec "<<rec<<"\n";
                       cout<<p<<"\n";
                    }
                    else   cout<<"Part not found\n";
                }
                break;

     case 'u': cout<<"Update ";
               if ( p.get_key() )
               {
                   if ( ( rec=f.search(p) ) != 0 )
                   {
                         cout<<p<<"\n";
                         cout<<"Enetr new part info: \n";
                         p.input();
                         if ( !p.isnull() )
                         {
                            if ( f.update(p, rec) )
                                   cout<<"Part successfully update\n";
                            else   cout<<"Error updating part\n";
                         }
                         else cout<<"Part not changed\n";
                      
                   }
                   else cout<<"Part not found\n";
               }
               break;

case 'd':  cout<<"Delete ";
           if ( p.get_key() )
           {
             if( ( rec=f.search(p) ) !=0)
             {
                cout<<p<<"\n";
                cout<<"Do you still wish to delete? ";
                cin>>c;
                if ( c=='y' || c=='Y' ) 
                {
                  if ( f.del(p, rec) )
                     cout<<"Part deleted\n";
                  else  cout<<"Error deleting part\n";
                 }
                         
                else cout<<"Part not deleted\n";
              }
              else cout<<"Part not found\n";
            }
           break;

case 'a':  cout<<"Enter part to add below: \n";
           p.input();
           if ( !p.isnull() ) 
           {
             if ( ( rec=f.add(p) ) != 0 ) 
             {
                 cout<<"Part stored at rec "<<rec<<"\n";
                 cout<<p<<"\n";
             }
           }
           break;

case 'l':  f.list(cout);
                 break;
     
     case 'h':  menu();
                 break;
     }
    return act;
}

int main()
{
   db<part> f;
   int i;
   menu();
     while(1)
    {
        i=get_action();
        if ( i =='q') break;
        do_action(f, i);
     };
}

% g++ problem.c -o problem
problem.c:309: template for method `update' doesn't match any in class `db<part>'
problem.c:309: template for method `del' doesn't match any in class `db<part>'




But, if I change  it into the following  :
     .
     .
     . ( all the parts of the program is kept the same except :  )
class db:   public file_of<part>
{
protected:
    unsigned nrecs;
    unsigned nitems;

public:
    db(void): nrecs(0), nitems(0) {}
    void update_header(void);
    void read_header(void);
    int open(char* fname, enum access_mode mode);
    int close(void);
    unsigned search(part& p);
    unsigned add(part& p);
   unsigned del(part& p, unsigned recno=0);
   unsigned update(part& p, unsigned recno=0);
    void list(ostream& strm);
};

void db::read_header(void)
{
   part p;
   cout<<"Enter read_header() \n";
   read( p, 0);
   cout<<" finish read_header()\n"; 
   memcpy(&nrecs, &p, 4);
   memcpy(&nitems,((char*)&p)+4, 4);
   cout<<"nrecs= "<<nrecs<<"nitems= "<<nitems<<"\n";

}


void db::update_header(void)
{
   part p;
          
   memcpy(&p, &nrecs, 4);
   memcpy(((char*)&p)+4, &nitems, 4);
   write(p, 0);
}


int db::open(char* fname, enum access_mode mode)
{

  cout<<"fname= "<<fname<<endl;
  cout<<"mode= "<<mode<<endl;
  recfile::open(fname, mode);
  cout<<" db::open opened= "<<opened<<"\n";
  if ( opened && mode == f_update )
          read_header();
  return opened;
}

int db::close(void)
{
   if ( opened ) update_header();
   return recfile::close();
}

unsigned db::search(part& p)
{
   unsigned r;
   part q;
   for ( r =1; r<= nrecs; r++ )
   {
        if ( read(q,r) && q.same_key(p) )
        {
              p=q;
              return r;
        }
    }
    return 0;
 }

unsigned db::add(part& p)
{
  unsigned r;
  part q;
  r = search(q);
  if ( r ) 
  {
    if ( write(p,r) )
    {
      nitems++;
      update_header();
      return r;
    }
  }
 else
 {
    if ( write(p, nrecs+1) )
    {
      nrecs++; nitems++;
      update_header();
      return nrecs;
    }
  }
  return 0;
}

unsigned db::del(part& p, unsigned recno)
{
  unsigned r;
  if ( recno ) r = recno;
  else r = search(p);
 if ( r )
 {
    part q;
    write(q,r);
    nitems--;
    update_header();
   }
  return r;
}

unsigned db::update(part& p, unsigned recno)
{
   unsigned r;
   if ( recno) r = recno;
   else r= search(p);
   if ( r ) 
   {
        write(p, r);
   }
   return r;
}

void db::list(ostream& strm)
{
  int cur_rec, recs_seen;
  part p;
  
  for ( cur_rec = 1, recs_seen = 0;
        cur_rec <= nrecs && recs_seen < nitems;
        cur_rec++)
  {
    read(p, cur_rec);
    if ( !p.isnull() )
    {
      strm<<p<<"\n";
      recs_seen++;
    }
   }
}

.
.
.

int main( ){
    db f;
    .
    .
    . 
}

then the program is ok, no compiling errors. I can run it. 
what's the problem? maybe I can not do this? : 

template<class T>
class file_of: public recfile{
    .......... }

template<class T>
class db:   public file_of<T>
{    ........... }


if someone  can give me the answer , I appreciate it vry much.
Thanx lot for help in advance.
my E_Mail :  lih@ucunix.san.uc.edu