Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should the pure virtual destructor be declared?

EDIT: Apparently the question is not clearly formulated enough. The issue I am having is that when the destructor is defined in the header it gets added into multiple .obj files and the linker complains. The actual question is:

When I add the destructor to a CPP file in a DLL project and use the dll with dynamic loading and the interface header file, does the base destructor still get called to prevent leaking memory?

I am using MSVC 10.0 and have a DLL project that implements an interface. The interface is an abstract (pure virtual) base class. The idea is that the header is used with dynamic loading of the library. Therefore, I have used a pure virtual destructor to make sure the destructor in the base class gets called. Here is sample code to explain this:

//ISplitter.h
#pragma once

struct param {
    int something;
}

class ISplitter {
public:
    virtual ~ISplitter() = 0;
    virtual void useful() = 0;
}

ISplitter::~ISplitter() {
    /* Make sure base class destructor gets called */
}

And the main implementation header

//CSplitter.h
#pragma once
#include "CHelper.h"
#include "ISplitter.h"


class CSplitter : public ISplitter {
private:
    CHelper hlp;
public:
    ~CSplitter();
    void useful();
}

Some helper class

//CHelper.h
#pragma once
#include "ISplitter.h" // I need the struct

// Class definition should go here but is irrelevant

Now the problem is that the linker generates an error that tells me the destructor: ISplitter::~ISplitter(void) has been multiply declared and the system will not build. Error:

CHelper.obj : error LNK2005: "public: virtual __cdecl ISplitter::~ISplitter(void)" (??1ISplitter@@UEAA@XZ) already defined in CSplitter.obj

What is the correct way to fix this? I have placed the destructor in ISplitter.cpp, but I am worried this may not work if I dynamically load the library and upcast the base class to ISplitter.

like image 385
Wouter Simons Avatar asked Jan 19 '23 15:01

Wouter Simons


2 Answers

The problem is that the base class destructor always gets called- but in this case, you've made it pure virtual, so it doesn't exist. The only reason to make a destructor pure virtual to is to enforce a class to be abstract when you have no other members. The destructor of a class needs to be defined in all cases.

Edit: I mis-read your code. Just define the destructor virtually inline.

virtual ~ISplitter() {}

There's no need for any pure virtual here, since you already have other pure virtual members.

like image 126
Puppy Avatar answered Jan 28 '23 01:01

Puppy


Sharptooth's answers is correct in that you HAVE to provide a definition to the pure virtual destructor (see this GotW). But it is wrong in that you cannot write

virtual ~A() = 0 {};

according to this clause in the standard (although many compilers support this extension)

Clause 10.4 paragraph 2 of C++03 tells us what an abstract class is and, as a side note, the following:

[Note: a function declaration cannot provide both a pure-specifier and a definition —end note] [Example:

struct C {
virtual void f() = 0 { }; // ill-formed
};

—end example]

See this question of mine for more details

like image 31
Armen Tsirunyan Avatar answered Jan 28 '23 01:01

Armen Tsirunyan