Creating an Interface Without Inheritance?

Hello there!

So I have a rather odd set of circumstances. I have one DLL that has a class defined with no interface, so it doesn't inherit from an abstract class with pure virtual functions. However I do know what those functions are like Vector GetVelocity() For the purpose of this question, assume that I cannot change the contents of the code of this DLL and that it's part of a larger project.

I have a second DLL in which it would be useful to be able to access functions from the aforementioned class. I can get a pointer to objects of this class as a void*, however, I cannot magically create an abstract interface class to do a reinterpret_cast.

It would look something like this IF I could:

class IActor
{
virtual Vector GetVelocity() = 0;
}

So my question is, is there any way to create an interface to a class without it being inherited from? Could I abuse my void* in some way to get a pointer to a function in the class?

Any help is greatly appreciated. I'm just not quite sure if this is even possible.
...class defined with no interface
To me, this means that your class (calling it class ActorA) has no public members and no associated free functions. But you seem to be using it differently, in that your class does not inherit from an abstract class, or maybe that it's not a part of an inheritance hierarchy. Correct me if I'm mistaken.

Is there any way to create an interface for a class without it being inherited from?

Yes. Ultimately, you need to handle multiple unrelated classes. As is common with this problem, you have two choices: either
a. erase the type of the unrelated classes; or
b. preserve the type of the unrelated classes in (e.g.) a discriminated union.

This thread discusses these two techniques near the bottom:
http://www.cplusplus.com/forum/beginner/217282/

Here is a toy example of a solution implementing choice a.:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# include <functional>
# include <iostream>
# include <memory>
# include <string>
# include <utility>

namespace dll {
  // Two unrelated classed implement the same functions.
  // They cannot be modified
  struct ActorA {
    std::string f1() const { return "ActorA::f1()"; }
    std::string f2() const { return "ActorA::f2()"; }
  };

  struct ActorB {
    std::string f1() const { return "ActorB::f1()"; }
    std::string f2() const { return "ActorB::f2()"; }
  };

  // Just for example:
  void* make_actorb() { return new ActorA; }
  void* make_actora() { return new ActorA; }
}

class Actor {
  struct IActor { virtual std::string f1() const = 0, f2() const = 0; };

  // Concrete actor.
  template <typename Erased>
  struct CActor: public IActor {
    template <typename U> explicit CActor(U &&u) : a(std::forward<U>(u)) {}

    std::string f1() const override { return a->f1(); }
    std::string f2() const override { return a->f2(); }

  private:
    Erased a;
  };

  // For example:
  std::unique_ptr<IActor> actor;

public:
  Actor() = default;
  template <typename T>
  explicit Actor(T&& t)
    : actor{std::make_unique<CActor<T>>(std::forward<T>(t))}
  {}

  std::string f1() const { return actor? actor->f1(): ""; }
  std::string f2() const { return actor? actor->f2(): ""; }
};

Actor make_actora()
{ return Actor{static_cast<dll::ActorA*>(dll::make_actora())}; }
Actor make_actorb()
{ return Actor{static_cast<dll::ActorB*>(dll::make_actorb())}; }

int main() {
  Actor a = make_actora();
  Actor b = make_actorb();

  std::cout << a.f1() << '\n'
            << a.f2() << '\n'
            << b.f1() << '\n'
            << b.f2() << '\n';
}

Live demo:
http://coliru.stacked-crooked.com/a/ad9ace6c286aa188
Last edited on
Also related is the implementation technique used when designing canonical dynamic dispatch in C:
https://stackoverflow.com/a/17622474/2085046

It's an option here too (with the help of a wrapper class.) void* does type erasure too, although it's less sophisticated.
Last edited on
Topic archived. No new replies allowed.