2010-03-31 20 views
5

Ho un errore di collegamento in cui il linker si lamenta che il distruttore della mia classe concreta chiama il distruttore astratto della superclasse, il cui codice manca.Errore linker: desidera il distruttore di classe base virtuale C++

Questo sta utilizzando GCC 4.2 su Mac OS X da XCode.

Ho visto g++ undefined reference to typeinfo ma non è esattamente la stessa cosa.

Ecco il messaggio di errore di linker:

Undefined symbols: 
    "ConnectionPool::~ConnectionPool()", referenced from: 
     AlwaysConnectedConnectionZPool::~AlwaysConnectedConnectionZPool()in RKConnector.o 
ld: symbol(s) not found 
collect2: ld returned 1 exit status 

Ecco l'abstract dichiarazione di classe di base:

class ConnectionPool { 
public: 
    static ConnectionPool* newPool(std::string h, short p, std::string u, std::string pw, std::string b); 
    virtual ~ConnectionPool() =0; 
    virtual int keepAlive() =0; 
    virtual int disconnect() =0; 
    virtual sql::Connection * getConnection(char *compression_scheme = NULL) =0; 
    virtual void releaseConnection(sql::Connection * theConnection) =0; 
}; 

Ecco la dichiarazione della classe concreta:

class AlwaysConnectedConnectionZPool: public ConnectionPool { 
protected: 
    <snip data members> 
public: 
    AlwaysConnectedConnectionZPool(std::string h, short p, std::string u, std::string pw, std::string b); 
    virtual ~AlwaysConnectedConnectionZPool(); 
    virtual int keepAlive(); // will make sure the connection doesn't time out. Call regularly 
    virtual int disconnect(); // disconnects/destroys all connections. 
    virtual sql::Connection * getConnection(char *compression_scheme = NULL); 
    virtual void releaseConnection(sql::Connection * theConnection); 
}; 

Inutile dire , tutti quei membri sono implementati. Qui è il distruttore:

AlwaysConnectedConnectionZPool::~AlwaysConnectedConnectionZPool() 
{ 
    printf("AlwaysConnectedConnectionZPool destructor call"); // nothing to destruct in fact 
} 

e forse anche la routine di fabbrica:

ConnectionPool* ConnectionPool::newPool(std::string h, short p, std::string u, std::string pw, std::string b) 
{ 
    return new AlwaysConnectedConnectionZPool(h, p, u, pw, b); 
} 

posso risolvere questo problema artificialmente facendo la mia classe di base astratta concreta. Ma preferirei fare qualcosa di meglio. Qualche idea?

Grazie

risposta

28

Anche se si dichiara un distruttore come una funzione virtuale pura, è necessario fornire un'implementazione per esso. Sebbene non sia possibile istanziare direttamente una classe astratta, essa viene sempre istanziata quando istanziate una delle sue classi derivate (concrete). E così ad un certo punto tali casi saranno distrutti, richiedendo così un distruttore. L'attuazione del distruttore virtuale puro può essere (e di solito è) una funzione vuota:

ConnectionPool::~ConnectionPool() { 
} 
+2

La risposta implica questo, ma vale la pena sottolineare che nei metodi astratti C++ * può * avere implementazioni. Sono stato sinceramente sorpreso quando ho scoperto, prima ho sempre pensato a metodi come astratti o di implementazione, non entrambi. – sbk

+0

@sbk Che non è corretto. In C++ abstract significa _pure_ virtual. Una funzione _non-pure_ virtual non è astratta, né rende astratta la sua classe. – Zimano

+0

@Zimano: quale parte del mio commento non è corretta? Sono d'accordo che "puro virtuale" e "astratto" sono la stessa cosa. Stavo dicendo che in C++ astratto/metodi virtuali puri * può * avere corpi/implementazione e distruttori, anche astratti, * deve * averne uno. Cioèil snippet '' 'classe A {virtuale ~ A() = 0 {}}' '' è valido – sbk

5

Anche in una classe astratta, non volete il vostro distruttore di essere puro virtuale. Questo perché verrà chiamato quando viene chiamato un distruttore di sottoclasse concreta.

Utilizziamo il seguente schema.

foo.h

class AbstractBaseClass { 
public: 
    virtual ~AbstractBaseClass(); 
    virtual void method1() = 0; 
    virtual void method2() = 0; 
protected: 
    AbstractBaseClass() { 
    } 
}; 

foo.cpp

AbstractBaseClass::~AbstractBaseClass() { 
} 

Vai a questa FAQ for details.

+0

Vuoi che sia puro virtuale , devi solo fornire un'implementazione. Anche il link che hai postato non affronta i distruttori virtuali puri. –

+1

@MPG: Ci possono essere delle volte in cui vuoi dichiarare una classe base astratta (una che non può essere istanziata), ma tu trovi te stesso senza funzioni virtuali - puoi sempre dichiararti distruttore pure virtuale - quindi come dice Neil che deve avere un'implementazione (non sono sicuro di averlo capito). – quamrana

+1

@Neil: se la classe base astratta ha altri metodi puramente virtuali, non c'è alcun motivo particolare per cui il dtor sia pure (per quanto ne so io comunque). E come dici, è necessario avere un'implementazione. Considerando entrambe queste premesse, non c'è motivo per cui il dtor debba essere un metodo puramente virtuale - e metterei in discussione la logica di una classe in cui l'unico metodo virtuale era il dtor. –

Problemi correlati