2009-10-08 14 views
5

Wie C# typeof-Befehl Verhalten in C++ zu simulieren?Wie typeof in C++

C# Beispiel:

public static PluginNodeList GetPlugins (Type type) 
{ 
... 
} 

Call:

PluginManager.GetPlugins (typeof(IPlugin)) 

Wie dies mit C++ implementieren? Vielleicht bieten QT- oder Boost-Bibliotheken eine Lösung?

Was ist mit dem Fall, wenn Sie .GetPlugins (...) auf eine Weise implementieren möchten, dass es diese Art von Objekten aus einer Datei (.so oder .dll) lädt?

+0

Was ist mit dem zweiten Teil meiner Frage. Für mich ist es das Schwierigste und ein Problem, dem ich immer wieder gegenüberstehe. Würde sehr geschätzt, wenn jemand mich in die richtige Richtung zeigen könnte. –

Antwort

2

Wenn Sie ein vollständiges typenartiges Verhalten wünschen, müssen Sie RTTI (run-time type information) verwenden. Bei vielen Compilern müssen Sie die Verwendung von RTTI explizit aktivieren, da dies einen Laufzeit-Overhead verursacht.

Dann können Sie typeid oder dynamic_cast verwenden, um den Typ eines Objekts zu finden.

Wenn Sie Typid nicht verwenden möchten, müssen Sie Vererbung, Zeiger und/oder Überladungen verwenden. Boost könnte Ihnen helfen, aber es ist nicht zu schwer.

Beispiel 1:

class Iplugin { ... } 

class Plugin1 : public Iplugin { ... } 
class Plugin2 : public Iplugin { ... } 

void getplugins(Iplugin* p) { 
    // ... you don't know the type, but you know 
    // what operations it supports via Iplugin 
} 

void getplugins(Plugin1& p) { 
    // expliticly handle Plugin1 objects 
} 

Wie Sie mehrere Möglichkeiten sind zu vermeiden Nutzung von RTTI und typeid sehen dort kann.

+1

Es ist wichtig, dass das stattfindende Casting über eine Klasse mit einer vtable stattfindet - RTTI ist darauf angewiesen, dynamic_cast durchzuführen. – fbrereto

+1

Ich glaube nicht, dass RTTI einen Laufzeitaufwand verursacht. Der generierte Code ist etwas größer, da die zusätzlichen Informationen pro Klasse mit der vtable gespeichert werden müssen. Wie erwähnt, muss die Klasse eine vtable haben. Solch eine Klasse sollte fast immer einen virtuellen Destruktor haben (der auch dafür sorgt, dass es eine vtable hat). – TrayMan

+1

indirekt kann es Laufzeit Overhead aufgrund der größeren Code-Größe verursachen. – rlbond

8

könnten Sie eine dynamic_cast verwenden Typen zu testen, wie unten dargestellt:

IPlugin* iPluginPtr = NULL; 
iPluginPtr = dynamic_cast<IPlugin*>(somePluginPtr); 

if (iPluginPtr) { 
    // Cast succeeded 
} else { 
    // Cast failed 
} 
+2

Beachten Sie, dass RTTI aktiviert sein muss, damit dies funktioniert. – csl

+13

Nun ja, mit anderen Worten, die Sprache muss C++ sein. Standard C++ enthält RTTI. Die Tatsache, dass Compiler das Ausschalten ermöglichen, sollte nicht relevant sein. Dies ist nicht standardmäßiges Verhalten. Wenn du anfängst Teile der Sprache zu deaktivieren, * natürlich * funktioniert dein Code nicht mehr. Sie können auch darauf hinweisen, dass der Code zu einem C++ - Compiler statt Fortran oder C zugeführt werden muss. – jalf

+1

@jalf: Ok, Sie haben mich überzeugt - es sollte irrelevant sein, was Compiler tun. Aber sie tun es, also tut es nicht weh zu bemerken, was Sie in der Praxis tun müssen. Ich schätze, Compiler machen das so, dass Sie "nicht für das bezahlen, was Sie nicht verwenden". – csl

5

Dieses Verhalten wird RTTI (Run time type information) genannt. Diese Technik ist am besten zu vermeiden, kann aber in manchen Situationen nützlich sein.

Es gibt zwei große Möglichkeiten, dies zu lösen. Die erste Möglichkeit besteht darin, eine Schnittstelle mit einer rein virtuellen Funktion zu schreiben, die einen klassenspezifischen Ganzzahlreferenzcode zurückgibt. Dieser Code kann dann verwendet werden, um einen bestimmten Typ darzustellen. Diese Ganzzahlen könnten in einer bestimmten Aufzählung gespeichert werden.

In abgeleiteten Klassen können Sie dann die Methode überschreiben und diesen klassenspezifischen Typ zurückgeben. Während der Laufzeit können Sie dann beispielsweise Plugin-> getType() aufrufen, und es wird seinen spezifischen Typ zurückgegeben. Sie können dann einen static_cast für den Zeiger ausführen, um den richtigen Zeiger des abgeleiteten Typs zurück zu erhalten.

Die zweite Möglichkeit besteht darin, entweder typeid zu verwenden, um den Klassentyp des Objekts zu erhalten; aber das ist compilerabhängig. Sie können auch versuchen, den Zeiger mithilfe von dynamic_cast zu werfen. dynamic_cast gibt einen Nullzeiger zurück, wenn er in den falschen Typ umgewandelt wird. und eine gültige, wenn sie in einen korrekten Typ umgewandelt wird. Die dynamische Cast-Methode hat einen größeren Overhead als die oben beschriebene getType-Methode.

+0

RTTI muss typsicheres dynamisches Downcasting durchführen. Es bietet keine "typeof" (GCC-Erweiterung) oder "auto"/"decltype" (C++ 0x) -Funktionalität. – Adisak

2

Um dieses Problem zu entwerfen, wäre die beste Wahl. Eine gute Verwendung der Objektorientierung kann normalerweise hilfreich sein, aber Sie können immer Ihr eigenes System zum Abfragen des Typs eines Objekts erstellen, indem Sie eine Basisklasse verwenden, die beispielsweise eine Kennung für jedes Objekt speichert.

Versuchen Sie immer, dynamic_cast zu vermeiden, da es den String-Vergleich am häufigsten verwendet, um den Typ eines Objekts zu finden, und das macht es wirklich langsam.

1

Boost hat eine Art von. C++ 0x nennt es nicht typeof, sondern hat sowohl 'auto' als auch 'declltype', die die gleiche Funktionalität bieten.

Das heißt, ich bin mir ziemlich sicher, keiner von denen bietet, was Sie wirklich in diesem Fall suchen - höchstens bieten sie nur ein kleines Stück von dem, was Sie insgesamt brauchen/wollen.

2

Sie können typeof() in GCC verwenden. Bei anderen Compilern wird es entweder nicht unterstützt oder du musst verrückte Template-Mangling machen oder "Bug-Features" verwenden, die sehr Compiler-spezifisch sind (so wie es Boost macht).

0

Ich antworte nicht direkt auf die "Wie bekomme ich typeof() in C++", aber ich folge aus Ihrer Frage, dass Sie sich mit Plugins in C++ beschäftigen. Wenn das der Fall ist, könnten Sie an der (noch nicht vorhandenen) Boost.Extension-Bibliothek und vielleicht an ihrem reflection Teil interessiert sein.

1

Sicher würden Sie nur überladen?

static PluginManager::GetPlugins(Type1 &x) { 
    // Do something 
} 

static PluginManager::GetPlugins(Type2 &x) { 
    // Do something else 
} 

und dann rufen:

PluginManager::GetPlugins(IPlugin);