2010-03-31 5 views
5

У меня есть ошибка ссылки, где компоновщик жалуется, что деструктор моего конкретного класса вызывает его абстрактный деструктор суперкласса, код которого отсутствует.Ошибка компоновщика: хочет уничтожить виртуальный базовый класс C++

Это использование GCC 4.2 на Mac OS X от XCode.

Я видел g++ undefined reference to typeinfo, но это не совсем то же самое.

Вот сообщение об ошибке линкер:

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

Вот абстрактные декларации базовый класс:

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

Вот конкретное объявление класса:

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

Излишне говорить , все эти члены реализованы. Вот деструктор:

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

, а также, возможно, рутина фабрика:

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

я могу исправить это искусственно сделать свой абстрактный базовый класс бетона. Но я лучше сделаю что-нибудь получше. Есть идеи?

Благодаря

ответ

28

Даже если объявить деструктор как чисто виртуальной функции, вы должны обеспечить реализацию для него. Хотя вы не можете создать экземпляр абстрактного класса напрямую, он всегда создается, когда вы создаете экземпляр одного из его производных (конкретных) классов. И поэтому в какой-то момент такие экземпляры будут уничтожены, что потребует деструктора. Реализация чистого виртуального деструктора может быть (и обычно есть) пустая функция:

ConnectionPool::~ConnectionPool() { 
} 
+2

Вы отвечаете на это, но стоит подчеркнуть, что в абстрактных методах C++ * могут * иметь реализации. Я был искренне удивлен, когда узнал, что до этого я всегда думал о методах как абстрактных, так и о реализации, а не о том и другом. – sbk

+0

@sbk Это неверно. В C++ абстрактный означает _pure_ virtual. Виртуальная функция _non-pure_ не является абстрактной и не делает ее абстрактной. – Zimano

+0

@ Zimano: в какой части моего комментария неверно? Я согласен, что «чисто виртуальный» и «абстрактный» - это одно и то же. Я говорил, что в C++ абстрактные/чистые виртуальные методы * могут * иметь тела/реализацию и деструкторы, даже абстрактные, * должны * иметь один. То естьфрагмент '' 'class A {virtual ~ A() = 0 {}}' '' действителен – sbk

5

Даже в абстрактном классе, вы не хотите, чтобы ваш деструктор быть чисто виртуальным. Это потому, что он будет вызван при вызове деструктора конкретного подкласса.

Мы используем следующий шаблон.

foo.h

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

foo.cpp

AbstractBaseClass::~AbstractBaseClass() { 
} 

Смотрите эту FAQ for details.

+0

Вы хотите, чтобы он был чистым виртуальным , вам просто нужно обеспечить реализацию. Также ссылка, которую вы опубликовали, не касается чистых виртуальных деструкторов. – 2010-03-31 17:50:11

+1

@MPG: могут быть случаи, когда вы хотите объявить абстрактный базовый класс (тот, который не может быть создан), но вы находите свое «я» без виртуальных функций - вы всегда можете объявить вас деструктором чистого виртуального, - тогда как Нил говорит, что он должен имеют реализацию (я не уверен, что я это понял). – quamrana

+1

@Neil: если абстрактный базовый класс имеет другие чистые виртуальные методы, нет никакой особой причины для того, чтобы dtor также был чистым (насколько я могу судить). И, как вы уже упоминаете, требуется реализация. Учитывая оба этих предпосылки, нет причин, по которым dtor должен быть чистым виртуальным методом - и я бы поставил под сомнение обоснование для класса, где единственным чистым виртуальным методом был dtor. –

Смежные вопросы