893 Stimmen

Wie deklariert man eine Schnittstelle in C++?

Wie kann ich eine Klasse einrichten, die eine Schnittstelle darstellt? Ist dies nur eine abstrakte Basisklasse?

4voto

Uri Punkte 86472

Eine kleine Ergänzung zu dem, was da oben steht:

Stellen Sie zunächst sicher, dass Ihr Destruktor ebenfalls rein virtuell ist

Zweitens sollten Sie bei der Implementierung vorsichtshalber virtuell (und nicht normal) vererben.

0 Stimmen

Ich mag die virtuelle Vererbung, weil sie konzeptionell bedeutet, dass es nur eine Instanz der geerbten Klasse gibt. Zugegeben, die Klasse hier hat keinen Platzbedarf, so dass sie vielleicht überflüssig ist. Ich habe mich schon eine Weile nicht mehr mit MI in C++ beschäftigt, aber würde nicht die nichtvirtuelle Vererbung das Upcasting erschweren?

0 Stimmen

Warum, oh warum, sollte jemand den dtor in diesem Fall rein virtuell machen wollen? Was wäre der Vorteil davon? Man würde den abgeleiteten Klassen nur etwas aufzwingen, das sie wahrscheinlich nicht brauchen - einen dtor.

2 Stimmen

Wenn es eine Situation gibt, in der ein Objekt durch einen Zeiger auf die Schnittstelle zerstört werden würde, sollten Sie sicherstellen, dass der Destruktor virtuell ist...

4voto

Nathan Xabedi Punkte 1077

In C++20 können Sie eine concept statt einer Klasse. Dies ist effizienter als Vererbung.

template <class T>
concept MyInterface = requires (T t) {
    { t.interfaceMethod() };
};

class Implementation {
public:
    void interfaceMethod();
};
static_assert(MyInterface<Implementation>);

Dann können Sie sie in einer Funktion verwenden:

void myFunction(MyInterface auto& arg);

Die Einschränkung besteht darin, dass Sie es nicht in einem Container verwenden können.

0 Stimmen

Vielleicht sollten Sie erklären, wie sich Schnittstellen von Konzepten unterscheiden, denn die Frage bezog sich auf Schnittstellen und nicht auf Konzepte in C++20. Sie sollten damit beginnen, die Syntax zu erklären und wie sie verwendet werden kann, IMHO.

1voto

lorro Punkte 5069

Es ist zwar richtig, dass virtual der De-facto-Standard für die Definition einer Schnittstelle ist, sollten wir nicht das klassische C-ähnliche Muster vergessen, das in C++ mit einem Konstruktor versehen ist:

struct IButton
{
    void (*click)(); // might be std::function(void()) if you prefer

    IButton( void (*click_)() )
    : click(click_)
    {
    }
};

// call as:
// (button.*click)();

Dies hat den Vorteil, dass Sie Ereignisse zur Laufzeit neu binden können, ohne Ihre Klasse neu konstruieren zu müssen (da C++ keine Syntax zum Ändern polymorpher Typen hat, ist dies ein Workaround für Chamäleonklassen).

Tipps:

  • Sie können von dieser Klasse als Basisklasse erben (sowohl virtuelle als auch nicht-virtuelle Klassen sind zulässig) und die click im Konstruktor Ihres Nachkommens.
  • Sie können den Funktionszeiger als protected Mitglied und haben eine public Referenz und/oder Getter.
  • Wie bereits erwähnt, können Sie damit die Implementierung zur Laufzeit ändern. Es ist also auch eine Möglichkeit, den Zustand zu verwalten. Abhängig von der Anzahl der if s vs. Zustandsänderungen in Ihrem Code, diese könnte schneller sein als switch() es oder if s (eine Trendwende wird für etwa 3-4 if s, aber messen Sie immer zuerst.
  • Wenn Sie wählen std::function<> über Funktionszeiger, müssen Sie könnte in der Lage sein, alle Ihre Objektdaten innerhalb IBase . Von diesem Punkt aus können Sie Werteschemata haben für IBase (z.B., std::vector<IBase> wird funktionieren). Beachten Sie, dass dies könnte je nach Compiler und STL-Code langsamer sein; außerdem sind die derzeitigen Implementierungen von std::function<> neigen dazu, im Vergleich zu Funktionszeigern oder sogar virtuellen Funktionen einen Overhead zu haben (dies könnte sich in Zukunft ändern).

0voto

Yeo Punkte 10530

Ich bin noch neu in der C++-Entwicklung. Ich habe mit Visual Studio (VS) begonnen.

Dennoch scheint niemand die Tatsache zu erwähnen, dass __interface in VS (.NET) . Ich bin no Ich bin mir nicht sicher, ob dies ein guter Weg ist, um eine Schnittstelle zu deklarieren. Aber es scheint eine zusätzliche Verstärkung (erwähnt in die Dokumente ). So müssen Sie nicht explizit die virtual TYPE Method() = 0; da es automatisch umgewandelt wird.

__interface IMyInterface {
   HRESULT CommitX();
   HRESULT get_X(BSTR* pbstrName);
};

Ich verwende es jedoch nicht, weil ich mir Sorgen über die plattformübergreifende Kompilierbarkeit mache, da es nur unter .NET verfügbar ist.

Wenn jemand etwas Interessantes darüber weiß, bitte mitteilen :-)

Danke.

0voto

rustyhu Punkte 1361

Falls Sie nur eine statische Bindung einer Schnittstelle wünschen (keine virtuelle, keine Instanzen des Schnittstellentyps selbst, Schnittstelle dient nur als Leitfaden):

#include <iostream>
#include <string>

// Static binding interface
// Notice: instantiation of this interface should be usefuless and forbidden.
class IBase {
 protected:
  IBase() = default;
  ~IBase() = default;

 public:
  // Methods that must be implemented by the derived class
  void behaviorA();
  void behaviorB();

  void behaviorC() {
    std::cout << "This is an interface default implementation of bC().\n";
  };
};

class CCom : public IBase {
  std::string name_;

 public:
  void behaviorA() { std::cout << "CCom bA called.\n"; };
};

class CDept : public IBase {
  int ele_;

 public:
  void behaviorB() { std::cout << "CDept bB called.\n"; };
  void behaviorC() {
    // Overwrite the interface default implementation
    std::cout << "CDept bC called.\n";
    IBase::behaviorC();
  };
};

int main(void) {
  // Forbid the instantiation of the interface type itself.
  // GCC error: ‘constexpr IBase::IBase()’ is protected within this context
  // IBase o;

  CCom acom;
  // If you want to use these interface methods, you need to implement them in
  // your derived class. This is controled by the interface definition.
  acom.behaviorA();
  // ld: undefined reference to `IBase::behaviorB()'
  // acom.behaviorB();
  acom.behaviorC();

  CDept adept;
  // adept.behaviorA();
  adept.behaviorB();
  adept.behaviorC();
  // adept.IBase::behaviorC();
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X