3

After writing a test, I determined that the this pointer in an interface is not equal to the this pointer of the concrete class, meaning I can't just use a C-style cast on it.

class AbstractBase {...};

class AnInterface {
public:
    AnInterface() {...} // need AbstractBase * here 
    ~virtual AnInterface() {...} // and here
};

class Concrete : public AbstractBase, public AnInterface {};

My interface needs a base class pointer to the concrete class inheriting it in the constructor and destructor in order to handle interface related registration and deregistration.

Every concrete object that inherits the interface needs to inherit the abstract base class first, it is always first in the layout.

For the constructor it is not all that hard, I can add a pointer in the interface constructor and pass this from the concrete class. But the destructor doesn't have any parameters, so I am in the dark there.

The solutions I came up with so far come with overhead:

1 - store the pointer in the interface to be used in the destructor - adds in one pointer worth of memory overhead

class AnInterface {
public:
    AnInterface(AbstractBase * ap) {...}
    ~virtual AnInterface() {...} // and here
private:
    AbstractBase * aPtr;
};

...
Concrete() : AnInterface(this) {}

2 - create an abstract method in the interface and implement it to return this in the concrete class - adds in the overhead of indirection for the virtual call

class AnInterface {
    virtual AbstractBase * getPtr() = 0;
};

class Concrete : public AbstractBase, public AnInterface {
    AbstractBase * getPtr() { return this; }
};

3 - dynamic_cast is even worse

Is there a more efficient way to achieve this?

  • 1
    You said, "My interface needs a base class pointer to the concrete class inheriting it". That seems to be a flaw in the design. – R Sahu Mar 16 '15 at 20:05
  • @RSahu - the interface is designed to work with the abstract base class but is decoupled form its design. I don't want to inherit the base class in the interface, because with multiple interfaces it will get messy. –  Mar 16 '15 at 20:06
  • Derive AnInterface from AbstractBase then? – berkus Mar 16 '15 at 20:08
  • @berkus - that's what I just said. It is not the only interface which works with the abstract base, so if a concrete class inherits 2 such interfaces, I would have 2 abstract bases in the inheritance chain... –  Mar 16 '15 at 20:12
  • @Bathsheba - they don't have to be, it just would have been nice if they were, then I could C cast the pointer and be done with it. –  Mar 16 '15 at 20:13
  • Firstly, using C-style casts is almost never the solution. Then, what's the problem with `dynamic_cast` and have you tried replacing your C-style cast with a simple `static_cast`? Of course, the static cast will only work if used on the actually right types. – Ulrich Eckhardt Mar 16 '15 at 20:24
  • @UlrichEckhardt - I found out that `static_cast` doesn't allow casts even if they are perfectly safe (relying on unique returned integer unique value, re-implemented for each object type) - but C casts works there just fine. –  Mar 16 '15 at 20:35
  • Have you tried `AbstractBase* p = static_cast(this)` inside `AnInterface`? The upcast to `Concrete*` should work, as should the implicit conversion to `AbstractBase*` afterwards. – Ulrich Eckhardt Mar 16 '15 at 20:44
  • @UlrichEckhardt - I am a little unclear on how is this supposed to work? As far as I know, compilers don't have psychic abilities, the interface is clueless about eventual classes in may be inherited by and their layouts, it could not possibly know how to adjust the pointer in the blind to magically make the necessary adjustment for each concrete class. –  Mar 16 '15 at 20:48
  • @dgtech if you inherit virtually, then there will be only 1 such base. – berkus Mar 17 '15 at 09:46
  • (I personally use method 2 from your list, as it's simple and predictable) – berkus Mar 17 '15 at 09:48

3 Answers3

2

IMO if decoupling between the base class and the interface is really needed, both solution 1 and 2 have tolerable overheads, certainly nothing that will be a problem on contemporary hardware.

But since you say that the interface is designed to work with the functionality, provided in the base class, then maybe the decoupling is not a good thing.

I mean if the problem is with inheriting multiple interfaces which all inherit the base class, or the "dreaded diamond" problem with inheritance, you can simply use virtual inheritance.

dtech
  • 47,916
  • 17
  • 112
  • 190
1

All of your concerns seem like micro-optimizations. Assuming you truly can't separate out your interface from your implementation (in which case, why are you using interfaces in the first place?) I would just use dynamic_cast and be done with it, even though it's pretty heavyweight. If I were stuck on a platform where RTTI isn't an option then I'd use option 2.

fluffy
  • 5,212
  • 2
  • 37
  • 67
1

Your design has some flaws.

You should consider using CRTP as from the Mixin aspect, which saves you from keeping an extra pointer of the concrete derived.

template<typename Derived>
class AnInterface {
public:
    AnInterface() {
       Derived* derived = static_cast<Derived*>(this);
       AbstractBase* abstractBase = static_cast<AbstractBase*>(derived);
    } // have AbstractBase * here 
    ~virtual AnInterface() {...} // and here
};

class Concrete 
: public virtual AbstractBase
, public AnInterface<Concrete> {
    AbstractBase * getPtr() { return this; }
};
Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190