2017-01-14 5 views
5

Angenommen, ich die folgenden Klassendefinitionenerbt Bedingtes von den reinen Basisklasse

struct base { 
    virtual int f() = 0; 
}; 

struct A: public base { 
    int f() final { return 1; } 
}; 

struct B: public base { 
    int f() final { return 2; } 
}; 

haben Ist es möglich, A und B in Vorlagen zu drehen, die einen bool Parameter nehmen, ob aus dem base oder nicht zu erben gibt? Ich habe Anwendungsfälle, die eine Basisklasse benötigen oder nicht, die eine gemeinsame Schnittstelle bereitstellt.

Angenommen, A und B haben viele Elementfunktionen, so dass die Duplizierung der Implementierung mühsam wäre. Aber sizeof(A) und sizeof(B) sind klein.

+0

Benötigen Sie zwei Versionen? Unter der Annahme, dass "base" nur abstrakte Funktionen enthält, sollten keine Laufzeitkosten entstehen. In Ihrem Beispiel sollte Ihr Optimierer sehen, dass jedes 'A' von dort' f() 'verwendet, da es' final' ist. – Guvante

+0

@Guvante: Er macht den Typ polymorph, was ihm eine vtable gibt. Keine Laufzeitkosten, aber trotzdem Kosten. – ildjarn

+0

@Guvante Die Größe des Erbtyps ist um die Größe eines Zeigers größer, der auf die Vtable zeigt. – SU3

Antwort

3

Ich kam mit dem direkteren Ansatz, den ich suchte, ohne Code-Duplizierung.

struct base { 
    virtual int f() = 0; 
}; 

struct empty_base { }; 

template <bool Inherit> 
struct A final: public std::conditional_t<Inherit,base,empty_base> { 
    int f() { return 1; } 
}; 
4

Sure:

template <bool> struct A 
{ 
    // ... 
}; 

template <> struct A<true> : base 
{ 
    // ... 
}; 

(Beachten Sie, dass Sie A<true> von A<false> ableiten lassen könnten, wenn die Redundanz vermeidet.)

Zum Beispiel:

template <bool> struct A 
{ 
    void f() { std::cout << "A::f called\n"; } 
}; 

template <> struct A<true> : A<false>, base 
{ 
    void f() override { A<false>::f(); } 
}; 

int main() 
{ 
    A<false> a1; 
    A<true> a2; 
    a1.f(); 
    a2.f(); 
    static_cast<base&>(a2).f(); 
} 
+0

Ich dachte mir, dass dies nicht für 'A a; Basis * p = & a; p-> f(); 'um richtig zu funktionieren. Ich denke, das würde nur passieren, wenn 'base :: f()' nicht abstrakt ist (diamond problem). Führt Ihre Implementierung den 'p-> f()' Aufruf langsamer als in meiner ursprünglichen Implementierung? – SU3

+0

Gibt es eine Möglichkeit, 'A :: f()' 'final' zu machen? – SU3

+1

Sie müssten die Deklaration kopieren (und die andere über 'A :: f()') aufrufen. Auch wenn Sie 'f()' in 'A ' setzen, würde es nicht die 'base :: f()' als abstrakte Anforderung erfüllen. – Guvante

1

Da Sie eine reine Base verwenden Klasse Die Unterscheidung sollte nicht wichtig sein, da Ihr Optimierer den virtuellen Funktionsaufruf vermeiden wird, wenn Sie A::f() seit dort wi anrufen Es wird niemals eine abgeleitete Klasse sein, die eine andere Version von f() implementiert.

Auch können Sie stattdessen class A final : base tun, wenn Sie von A nicht planen, zu jeder Funktion hinzufügen final zu vermeiden, auf vererben.

+0

Danke. Ich habe vergessen, dass du "final" an der Klasse statt an Funktionen festhalten kannst. – SU3

+0

Sie können auch 'Klasse A versiegelt: öffentliche Basis {...};' –

+0

Was ist 'versiegelt'? Ist das eine Microsoft-Erweiterung? – SU3

Verwandte Themen