ora ho provato a rendere i metodi di lista come virtuali puri e a utilizzare i riferimenti a lista anzichè istanziare gli oggetti lista. il test viene compilato ma va in crash.

ho apportato le seguenti modifiche nel file lista.h (le modifiche sono segnate in rosso).

lista.h
codice:
#include <iostream>
#include <stdlib.h>

using namespace std;

template<class posizione, class tipoelem>
class lista
{
   public:
      virtual void crealista() = 0;
      virtual bool listavuota() = 0;
      virtual posizione primolista() = 0;
      virtual bool finelista(posizione) = 0;
      virtual posizione succlista(posizione) = 0;
      virtual posizione predlista(posizione) = 0;
      virtual tipoelem leggilista(posizione) = 0;
      virtual void scrivilista(posizione, tipoelem) = 0;
      virtual void inslista(posizione, tipoelem) = 0;
      virtual void canclista(posizione) = 0;
      
      void stampalista();
      void fondiordinate(lista &, lista &);
      void epurazione();
      void naturalmergesort();
   private:
      void distribuisci(lista &, lista &);
      void copiacatena(posizione, lista &, posizione, lista &);
      void copia(posizione, lista &, posizione, lista &, bool *);
      void merge(lista &, lista &, lista &, int *);
      void fondicatena(posizione, lista &, posizione, lista &, posizione, lista &);
      
};

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::stampalista()
{
   posizione p = primolista();
   while(!finelista(p))
   {
      cout << leggilista(p) << "\n";
      p = succlista(p);
   }
   cout << "\n";
}
   

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::fondiordinate(lista<posizione, tipoelem> &A, lista<posizione, tipoelem> &B)
{
   posizione pa = A.primolista();
   posizione pb = B.primolista();
   posizione pc = primolista();
   
   tipoelem elem1 = A.leggilista(pa);
   tipoelem elem2 = B.leggilista(pb);
   while(!A.finelista(pa) && !B.finelista(pb))
   {
      if(elem1 <= elem2)
      {
         inslista(pc, elem1);
         pa = A.succlista(pa);
      }
      else
      {
         inslista(pc, elem2);
         pb = B.succlista(pb);
      }
      elem1 = A.leggilista(pa);
      elem2 = B.leggilista(pb);
   }
   while(!A.finelista(pa))
   {
      inslista(pc, elem1);
      pa = A.succlista(pa);
      elem1 = A.leggilista(pa);
   }
   while(!B.finelista(pb))
   {
      inslista(pc, elem2);
      pb = B.succlista(pb);
      elem2 = B.leggilista(pb);
   }
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::epurazione()
{
   posizione p = primolista();
   posizione q;
   posizione t;
   while(!finelista(p))
   {
      q = succlista(p);
      while(!finelista(q))
      {
         if(leggilista(p) == leggilista(q))
         {
            t = succlista(q);
            canclista(q);
            q = t;
         }
         else
            q = succlista(q);
      }
      p = succlista(p);
   }
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::naturalmergesort()
{
   int numerocatene;
   lista<posizione, tipoelem> *A, *B, *L;
   do
   {
      A->crealista();
      B->crealista();
      distribuisci(*A, *B);
      numerocatene = 0;
      crealista();
      merge(*A, *B, *L, &numerocatene);
   }while(numerocatene != 1);
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::distribuisci(lista<posizione, tipoelem> &A, lista<posizione, tipoelem> &B)
{
   posizione p = primolista();
   posizione pa = A.primolista();
   posizione pb = B.primolista();
   do
   {
      copiacatena(p, *this, pa, A);
      if(!finelista(p))
         copiacatena(p, *this, pb, B);
   }while(!finelista(p));
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::copiacatena(posizione p, lista<posizione, tipoelem> &L, posizione pa, lista<posizione, tipoelem> &A)
{
   bool finecatena = false;
   do
      copia(p, L, pa, A, &finecatena);
   while(!finecatena);
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::copia(posizione p, lista<posizione, tipoelem> &L, posizione pa, lista<posizione, tipoelem> &A, bool *finecatena)
{
   bool esito = *finecatena;
   finecatena = &esito;
   tipoelem elemento = leggilista(p);
   A.inslista(pa, elemento);
   p = succlista(p);
   pa = succlista(pa);
   if(finelista(p))
      esito = true;
   else
      esito = (elemento > leggilista(p));
   finecatena = &esito;
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::merge(lista<posizione, tipoelem> &A, lista<posizione, tipoelem> &B, lista<posizione, tipoelem> &L, int *numcatene)
{
   posizione p = primolista();
   posizione pa = A.primolista();
   posizione pb = B.primolista();
   
   while(!A.finelista(pa) && !B.finelista(pb))
   {
      fondicatena(pa, A, pb, B, p, L);
      numcatene++;
   }
   while(!A.finelista(pa))
   {
      copiacatena(pa, A, p, L);
      numcatene++;
   }
   while(!B.finelista(pb))
   {
      copiacatena(pb, B, p, L);
      numcatene++;
   }
}

template<class posizione, class tipoelem>
void lista<posizione, tipoelem>::fondicatena(posizione pa, lista<posizione, tipoelem> &A, posizione pb, lista<posizione, tipoelem> &B, posizione p, lista<posizione, tipoelem> &L)
{
   bool finecatena = false;
   do
   {
      if(A.leggilista(pa) < B.leggilista(pb))
      {
         copia(pa, A, p, *this, &finecatena);
         if(finecatena)
            copiacatena(pb, B, p, *this);
      }
      else
      {
         copia(pb, B, p, *this, &finecatena);
         if(finecatena)
            copiacatena(pa, A, p, *this);
      }
   }while(finecatena);
}