Ошибка компоновщика: требуется деструктор виртуального базового класса C ++ - PullRequest
7 голосов
/ 31 марта 2010

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

Используется GCC 4.2 в Mac OS X из XCode.

Я видел g ++ неопределенную ссылку на 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);
}

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

Спасибо

Ответы [ 2 ]

33 голосов
/ 31 марта 2010

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

ConnectionPool::~ConnectionPool() {
}
4 голосов
/ 31 марта 2010

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

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

foo.h

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

foo.cpp

AbstractBaseClass::~AbstractBaseClass() {
}

Подробнее см. FAQ .

...