Erzwingen, virtuell von einer Klasse abzuleiten

8

Wir haben ein spezielles Framework für Schnittstellen in unserem Projekt, und ein Teil der Anforderungen besteht darin, dass Klassen, die eine Schnittstelle darstellen, nur als virtuelle Basisklassen und nicht als nicht-virtuelle Klassen verwendet werden dürfen. Gibt es eine Möglichkeit, dies in Code zu erzwingen? Das heißt, einen Kompilierungsfehler erzeugen, wenn die Klasse von nicht virtuell abgeleitet ist.

Ich habe Zugriff auf C ++ 11, wie von VS 2010 implementiert: das bedeutet static_assert , enable_if und <type_traits> sind verfügbar.

    
Angew 09.05.2013, 07:16
quelle

3 Antworten

3

IMO, es gibt keine saubere und plattformunabhängige Lösung für dieses Problem.

Der beste Weg ist, manuell jede einzelne Vererbung in virtual Vererbung zu ändern.
Um dies zu erreichen, ist es einfach (!), Die abgeleiteten Klassen Ihrer Schnittstelle (zB class Base ) zu identifizieren. Die folgenden Schritte können dafür ausgeführt werden:

  1. Machen Sie class Base als final (c ++ 11); d.h. class Base final { ...
  2. Kompilieren Sie den Code, es wird Compiler-Fehler für alle seine generieren abgeleitete Klassen
  3. Gehe und überprüfe jede abgeleitete Klasse und mache die Vererbung als %Code%
  4. Entfernen Sie das Schlüsselwort virtual und kompilieren Sie den Code erfolgreich

Dieser Prozess muss (leider) regelmäßig durchgeführt werden, wann immer Sie eine solche Überprüfung durchführen wollen.

    
iammilind 09.05.2013, 16:49
quelle
3

Dies kann zum Zeitpunkt der Kompilierung überprüft werden. Der Schlüssel ist, wenn wir ein Rautenmuster haben:

Sie können D& eindeutig auf A& anwenden. Wenn die Vererbung jedoch nicht virtuell ist:

Die Besetzung würde mehrdeutig sein. Also lass uns versuchen, einen Diamanten zu machen!

%Vor%

An diesem Punkt ist es nur ein weiterer void_t -Style-Typ:

%Vor%

Wenn die Besetzung eindeutig ist, ist der Ausdruck in der Teilspezialisierung gültig, und diese Spezialisierung wird bevorzugt. Wenn der Cast zweideutig ist, haben wir einen Substitutionsfehler und landen am Primary. Beachten Sie, dass Base hier nicht unbedingt virtual -Memberfunktionen haben muss:

%Vor%

Und wenn es reine virtuelle Elementfunktionen hat, müssen wir sie nicht überschreiben, da wir niemals ein Objekt konstruieren.

%Vor%

Natürlich, wenn Ihre Klasse final markiert ist, wird dies überhaupt nicht funktionieren. Aber wenn es final wäre, wäre es egal, welche Art von Vererbung es ohnehin hatte.

    
Barry 31.07.2015 15:27
quelle
1

Interessantes Problem. Sie können sich dem gewünschten Ziel nähern, indem Sie die Interface-Klasse verbergen und eine konkrete Klasse offenlegen, die virtuell von der Schnittstelle erbt. Dies bringt natürlich einige Umwege und Unannehmlichkeiten mit sich, aber es kann an Ihre Bedürfnisse angepasst werden. Hier ist ein Beispiel:

%Vor%

Es kann möglich sein, einen Namen mit decltype() und as_interface() zu rekonstruieren, der für die Vererbung geeignet sein könnte, aber die, die ich probiert habe, führten zu Compiler-Fehlern, die der Destruktor geschützt war. es ist zumindest relativ schwierig und könnte für Ihre Bedürfnisse ausreichen.

    
Adam H. Peterson 09.05.2013 16:32
quelle