3

I am new to C++11, and I am trying to build a classic interface / implementation pair. Consider the following sample:

#include <iostream>
#include <memory>

// Interface
class IFace {
public:
    virtual ~IFace () = 0;
};
// Why must I define this concrete implementation?
inline IFace::~IFace () { }

// Implementation
class Impl : public IFace {
public:
    virtual ~Impl () { }
};

int main (int argc, char ** argv) {
    auto impl = std::shared_ptr<Impl> (new Impl ());
    return 0;
}

If I comment out the undesirable concrete destructor on the interface inline IFace::~IFace () { }, I get link errors

Undefined symbols for architecture x86_64:
  "IFace::~IFace()", referenced from:
      Impl::~Impl() in ifac_impl.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I must do this even if the interface and implementation are templated:

// Template IFace2
template <typename T>
class IFace2 {
public:
    virtual ~IFace2 () = 0;
};
// I have to do this even if the pair is templated.
template <typename T>
inline IFace2<T>::~IFace2<T> () { }

template <typename T>
class Impl2 : public IFace2<T> {
public:
    virtual ~Impl2 () { }
};

int main (int argc, char ** argv) {
    auto impl = std::shared_ptr<Impl> (new Impl ());
    auto impl2 = std::shared_ptr<Impl2<double> > (new Impl2<double> ());
    return 0;
}

Why?

A second question is "am I going about this the wrong way?" That is, is there a better pattern (idiom?) for what I want to do? I am admittedly trying to fit a conceptual pattern I developed with C# into C++11. Is this sane? If not, what is the sane way?

Reb.Cabin
  • 5,426
  • 3
  • 35
  • 64

2 Answers2

7

When you override a virtual function in the derived class, and then invoke it, the base implementation is not called, unless you explicitly call it.

For instance,

struct base
{
  virtual void foo() {}
};

struct derived : base
{
  void foo() override {}
};

base *b = new derived;
b->foo();  // this will not call base::foo

The same applies to pure virtual functions as well.

However, in the case of a (pure) virtual destructor, the base destructor will be called (because the base sub-object needs to be destroyed). Hence, if you have a pure virtual destructor, you must provide an implementation. Otherwise you'll never be able to instantiate any derived class.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
6

The destructor should not be pure virtual. That would make the class abstract and therefore not possible to instantiate. Just define it as default:

class IFace {
public:
    virtual ~IFace () = default;
};

Live demo

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • But I want the interface classes to be abstract. I want (most of) the code that uses these classes to refer only to the interfaces. The only code that should "see" implementations is the code that calls constructors. The rest of the code should access implementations only through interfaces. I want this for testability and simulation purposes: in various scenarios, mocks and simulations of concrete implementations should be "injected" in place of other concrete implementations. This is the pattern I developed with C# -- strict separation of abstract and concrete. Is this not sane in C++11? – Reb.Cabin Jun 15 '14 at 22:53
  • 1
    @Reb.Cabin Then you need to find at least a function that could be pure virtual (and would make sense for it to be). If you don't have any, then you shouldn't probably be using inheritance. – Shoe Jun 15 '14 at 22:54
  • @Jeffrey Yes, in my actual code, I have many such pure virtual functions. I cut them down to make my question as small as possible. – Reb.Cabin Jun 15 '14 at 22:56
  • @Reb.Cabin A class is *abstract* so long as it has at least one pure virtual function. So you can make your destructor be virtual but non-pure and make your other interface functions be pure, and you still have a valid interface pattern. – M.M Jun 15 '14 at 23:00
  • @Matt Thanks, that seems clear to me. – Reb.Cabin Jun 15 '14 at 23:02
  • @Jeffrey -- how did you make the "Live Demo" button? I created a Coliro for an augmented version of my code here, http://coliru.stacked-crooked.com/a/e1a143b63b5a0c74, but don't see how to make a button out of it. – Reb.Cabin Jun 15 '14 at 23:03
  • @Reb.Cabin [See here](http://meta.stackexchange.com/q/70356/152998). – Shoe Jun 15 '14 at 23:05