Microsoft GDI + definiert viele leere Klassen, die behandelt werden sollen als handle intern. Zum Beispiel (source GdiPlusGpStubs.h
)
Es gibt zwei weitere Möglichkeiten zum Definieren von Handles. Sie sind,
%Vor%Ich möchte nur die Vor- und Nachteile jedes dieser Ansätze kennen.
Ein Vorteil von Microsofts Ansatz ist, dass sie typsichere Hierarchie von Handles mit leeren Klassen definieren können, was (glaube ich) mit den beiden anderen nicht möglich ist Ansätze, obwohl ich mich frage, welche Vorteile diese Hierarchie für die Implementierung bringen würde? Wie auch immer, was noch?
BEARBEITEN:
Ein Vorteil des zweiten Ansatzes (d. h. die Verwendung unvollständiger Klassen) besteht darin, dass wir verhindern können, dass Clients die Handles dereferenzieren (das heißt, dieser Ansatz scheint die Kapselung stark zu unterstützen, nehme ich an). Der Code würde nicht einmal kompilieren, wenn man versucht, Griffe zu dereferenzieren. Was noch?
Derselbe Vorteil, den man auch bei der dritten Methode hat, ist, dass die Griffe nicht dereferenziert werden können.
Approach # 1 befindet sich in der Mitte zwischen C-Stil und C ++ - Schnittstelle. Anstelle von Elementfunktionen müssen Sie das Handle als Argument übergeben. Der Vorteil von exponierten Polymorphismen besteht darin, dass Sie die Anzahl der Funktionen in der Schnittstelle reduzieren können und die Typen zur Kompilierzeit überprüft werden. In der Regel bevorzugen die meisten Experten pimpl idiom (manchmal Kompilierungs-Firewall genannt) für solche Schnittstellen. Sie können Approach # 1 nicht verwenden, um mit C zu interagieren, also gehen Sie besser zu C ++.
Ansatz Nr. 2 ist die C-Stil-Kapselung und das Ausblenden von Informationen. Der Zeiger kann (und ist oft) ein Zeiger auf echtes Ding sein, also ist er nicht überentwickelt. Der Benutzer der Bibliothek darf diesen Zeiger nicht dereferenzieren. Nachteil ist, dass es keinen Polymorphismus aussetzt. Vorteil ist, dass Sie es verwenden können, wenn Sie mit Modulen arbeiten, die in C geschrieben sind.
Ansatz # 3 ist eine zu stark abstrahierte C-artige Verkapselung. Der Zeiger kann tatsächlich überhaupt kein Zeiger sein, da der Benutzer der Bibliothek ihn nicht werfen, freigeben oder dereferenzieren sollte. Vorteil ist, dass es so Exception- oder Error-Werte mit sich bringt, Nachteil ist, dass die meiste Laufzeit überprüft werden muss.
Ich stimme DeadMG zu, dass sprachneutrale objektorientierte Schnittstellen sehr einfach und elegant aus C ++ zu verwenden sind, aber diese beinhalten auch mehr Laufzeitprüfungen als Kompilierzeitprüfungen und sind zuviel, wenn ich keine Schnittstelle brauche andere Sprachen. Also bevorzuge ich Approach # 2, wenn es mit C oder Pimpl Idiom interagiert, wenn es nur C ++ ist.
Approach 3 ist überhaupt nicht sehr gut, da es das Mischen und Abgleichen von Handle-Typen erlaubt, die eigentlich keinen Sinn ergeben. Jede Funktion, die einen HANDLE braucht, kann einen beliebigen GRIFF nehmen, selbst wenn es dafür kompilierbar ist ist der falsche Typ.
Der Nachteil von Ansatz 1 ist, dass Sie am anderen Ende eine Reihe von Castings auf ihre tatsächlichen Typen anwenden müssen.
Approach 2 ist nicht so schlimm, außer dass man keine Art von Vererbung damit machen kann, ohne jedes Mal extern nachfragen zu müssen.
All dies ist jedoch völlig unbegründet, seit Compiler entdeckt haben, wie man effiziente virtuelle Funktionen implementiert. Der Ansatz von DirectX und COM ist der beste - er ist sehr flexibel, leistungsstark und vollständig typsicher.
Es erlaubt sogar einige wirklich verrückte Dinge, wie Sie von DirectX-Schnittstellen erben und es auf diese Weise erweitern können. Einer der besten Vorteile davon ist Direct2D und Direct3D11. Sie sind nicht wirklich kompatibel (das ist wirklich, schrecklich dumm), aber Sie können einen Proxy-Typ definieren, der von ID3D10Device1 erbt und an das ID3D11Device weiterleitet und das Problem so löst. Diese Art von Sache würde niemals darüber nachdenken, mit irgendeinem der obigen Ansätze möglich zu sein.
Oh, und das Letzte: Du solltest deine Typen wirklich nicht in Allcaps benennen.
2 und 3 sind etwas weniger typsicher, da sie die Verwendung von Anfassern anstelle von void * ermöglichen
%Vor%Tags und Links c++ handles incomplete-type empty-class