2010-03-31 103 views
5

我有一个链接错误,其中连接器抱怨我的具体类的析构函数正在调用其抽象超类析构函数,其代码丢失。链接器错误:想C++虚拟基类析构函数

这是在XCode的Mac OS X上使用GCC 4.2。

我看到了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 2010-03-31 17:32:30

+0

@sbk这是不正确的。在C++中抽象意味着_pure_虚拟。一个_non-pure_虚函数不是抽象的,也不是抽象的。 – Zimano 2016-01-07 11:40:16

+0

@Zimano:我评论的哪部分内容不正确?我同意“纯虚拟”和“抽象”是一回事。我在说,在C++中,抽象/纯虚拟方法*可以具有body/implementation和destructor,即使是抽象的,也必须具有一个。即片段'''class A {virtual〜A()= 0 {}}'''是有效的 – sbk 2016-01-13 12:44:32

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:有时候你想要声明一个抽象基类(一个不能被实例化),但是你发现你的自己没有虚函数 - 你总是可以声明你是析纯函数的纯虚函数 - 然后就像Neil说的那样有一个实现(我不知道我是否意识到)。 – quamrana 2010-03-31 18:07:44

+1

@ Neil:如果抽象基类有其他纯粹的虚拟方法,那么dtor没有特别的理由也是纯粹的(就我所知,无论如何)。正如你所提到的,它需要有一个实现。考虑到这两个前提,dtor应该不是一个纯粹的虚拟方法 - 我会质疑这个类的唯一纯虚拟方法是dtor的基本原理。 – 2010-03-31 18:20:26