2

Coming from a Java/python world with little or no C++ experience, I am used to work with interfaces to separate the contract that a class has from its implementation, for the sake of the Liskov substitution principle and dependency injection.

I am not going to go over all the benefits of interfaces in Java, or why they were introduced (lack of multiple inheritance) and not needed in C++ (see here for example). I also found out how to have the equivalent of a Java interface in C++

My question is more about whether or not this is a good practice in a C++ environment.

As I understand it, there cannot be the equivalent of an interface without pure virtual methods. This means that bringing interfaces in C++ will introduce some overhead in the code (because virtual methods introduce an overhead).

Therefore, are interfaces based on pure virtual method a good thing? Is there maybe some other way to achieve the Liskov Substitution principle and dependency injection that I don't know of? using templates maybe?

For example, google test has it easy to mock virtual methods, but proposes a way of mocking non virtual methods.

I am trying to figure out if my coding habits are still relevant in my new C++ environment, or if I should adapt and change my paradigms.

[EDIT based on answers and comments]

I got part of the answer I was looking for (i.e. "yes/no with arguments"), and i guess I should clarify a bit more what I am still trying to figure out

  • Are there alternatives to using an interface-like design to do dependency injection?
  • Reversing the question: should one decide to go for an interface-based design, except when speed is absolutely crucial, when would one NOT want to do an interface based on pure virtual methods?

Notes:

  • I guess I'm trying to figure out if I'm too narrow minded thinking in terms of interfaces (hence my edit looking for alternatives).
  • I work in a C++ 11 environment
Arnaud Potier
  • 1,750
  • 16
  • 28
  • 2
    Depends on what you're doing. C++ is exposing multiple way to do polymorphism, including link-time polymorphism. – Guillaume Racicot Sep 19 '19 at 14:16
  • Are interfaces a good practice in C++? Yes – Martin G Sep 19 '19 at 14:32
  • Interfaces are a design-choice first and foremost, well emulated in C++ with a pure abstract base class. You can even [eliminate the v-table](https://stackoverflow.com/questions/8371470/how-do-i-suppress-c-vtable-generation-for-pure-virtual-classes-using-g), although that's a micro-optimization that is quite hard to notice. It is not going to be any slower than your Java code. – Hans Passant Sep 19 '19 at 14:32
  • [Here are some standard C++ interfaces](https://en.cppreference.com/w/cpp/named_req), of a kind that you haven't found – Caleth Sep 19 '19 at 14:36
  • @ admins, why putting it on hold and stop accepting answers? It's a good open-ended question and such discussion can benefit lots of people. – SPD Sep 19 '19 at 14:54
  • The main alternative to run-time polymorphism (interfaces) is compile-time polymorphism (templates, duck typing). Both are good practice for [DI](https://boost-experimental.github.io/di/) and other purposes. The choice between them is largely opinion based. If you're comfortable with one and it works for your task, there's no reason not to use it. – joshwilsonvu Sep 19 '19 at 17:27

1 Answers1

2

I would say interfaces are still a fine practice in C++. The overhead that virtual methods introduce is minimal, and as you will hear time and time again, premature optimization is a big mistake. Abstract base classes are a well-known, well-understood concept in C++ and favoring readable, common concepts over convoluted template metaprogramming can help you immensely in the long run.

That being said, I would try to avoid multiple inheritance. There are certain tricky issues that come with it, which is why Java explicitly forbids it for regular inheritance. A simple google search can give you more explanation.

If you have multiple unrelated classes and you'd like to call a method of the same name (let's say foo()) on each of them, then instead of an interface you can make a templatized function to do this.

class A {
  void foo() {
    // do something
  }
};

class B {
  void foo() {
    // do something
  }
};

template <typename T>
void callFoo(const T& object) {
  object.foo();
}

int main() {
  A a;
  B b;
  callFoo(a);
  callFoo(b);

  return 0;
}

Even though there is no explicit "contract" in callFoo() stating that the type must support .foo(), any object that you pass to it must support it or there will be a compile error. This is a commonly used way to duck-type objects at compile time and an alternative to interfaces for certain scenarios.

At the end of the day, as you learn more C++, you will use your own judgement to decide how you will accomplish the polymorphic behavior you want. There is no single right answer how to do it, just as there is no wrong answer either. Both abstract base classes and template duck typing are good tools that serve slightly different purposes.

joshwilsonvu
  • 2,569
  • 9
  • 20
  • choosing the right too from the start and premature optimization are two completely different things. If you dont want compile time polymorphism then it would be not good to go for runtime polymorphism just to avoid premature optimization – 463035818_is_not_an_ai Sep 19 '19 at 14:33
  • 1
    I'm just saying you shouldn't avoid virtual methods solely because they are "slow." – joshwilsonvu Sep 19 '19 at 14:34
  • ah ok, maybe I just misread. Once decided for runtime polymorphism one shouldnt worry too much about the overhead of virtual methods, that would be premature, I completely agree – 463035818_is_not_an_ai Sep 19 '19 at 14:36