2017-08-17 1 views
5

En Java, vous pouvez créer une carte qui mappe String en types d'objets génériques pouvant être explicitement castés vers d'autres classes. Est-il possible d'imiter cette fonctionnalité en C++?C++ Equivalent de Java Map <String, Object>

+0

Il existe une carte en C++ 11/14, std :: map. s'il vous plaît vérifier s'il pourrait répondre à vos besoins. – tibetty

+0

et aussi ['std :: unordered_map'] (http://fr.cppreference.com/w/cpp/container/unordered_map) –

+1

Je pense que op parle d'un objet de classe qui peut accepter n'importe quel type d'objet ... pas sur la collection de conteneurs de données Carte –

Répondre

1

Étant un langage assez fortement typé, C++ n'a pas de "type d'objet générique". Il a sûrement des conteneurs associatifs: std::map (une saveur d'arbre binaire) et std::unordered_map (une saveur de table de hachage). Le mieux dépend du cas d'utilisation et ne peut souvent pas être décidé sans profilage.

La chose la plus proche d'un objet générique que je peux penser est un ancêtre commun pour tous les objets qui pourraient être mis dans cette carte. Ici, l'idée est de créer une hiérarchie de classe avec un polymorphisme dynamique, et de stocker les objets dans la carte en tant que pointeurs dans cet ancêtre commun. La conception idéale rendrait inutile le retour de ces objets dans leur classe dérivée. Si à la place un tel cast est requis, il faudra utiliser un dynamic_cast (et éventuellement vérifier qu'il a réussi).

Il est obligatoire de stocker les pointeurs sur les objets de la carte, par opposition aux objets eux-mêmes. Sinon, parmi les objets que l'on essaie d'insérer dans la carte, seule la partie ancêtre commune serait stockée et le polymorphisme serait perdu. Il faut aussi décider si la carte possède les objets ou non (pas de ramassage des ordures ici). Sinon, des pointeurs simples peuvent fonctionner. Si la carte possède les objets, je vous recommande de les stocker enveloppés dans des "pointeurs uniques" (std::unique_ptr). enveloppait:

#include <unordered_map> 
#include <string> 
#include <memory> // std::unique_ptr<>, std::make_unique() 
#include <iostream> 

class NotSoGenericClass { 
    public: 
    virtual ~NotSoGenericClass() = default; 
    virtual std::string name() const 
    { return "NotTooGenericClass()"; } 
}; 

class EvenLessGenericClass: public NotSoGenericClass { 
    int fValue = 0; 
    public: 
    EvenLessGenericClass(int value): fValue(value) {} 
    virtual std::string name() const override 
    { return "EvenLessGenericClass(" + std::to_string(fValue) + ")"; } 
    int value() const { return fValue; } 
}; 

int main() { 
    // 
    // map holding (and owning) "not so generic objects" 
    // 
    std::unordered_map<std::string, std::unique_ptr<NotSoGenericClass>> allObjects; 

    // 
    // populate it 
    // 
    allObjects["any"] = std::make_unique<NotSoGenericClass>(); 
    allObjects["six"] = std::make_unique<EvenLessGenericClass>(6); 
    allObjects["one"] = std::make_unique<EvenLessGenericClass>(1); 

    std::cout << "Object 'six' says: " << allObjects["six"]->name() << std::endl; 

    std::cout << "Now dumping all " << allObjects.size() << " objects:"; 
    for (auto const& keyAndObject: allObjects) { 

    auto const& key = keyAndObject.first; 
    auto const* object = keyAndObject.second.get(); 

    // 
    // base class interface is always available: 
    // 
    std::cout << "\n[" << key << "] " << object->name(); 

    // 
    // object-specific one requires a cast: 
    // 
    auto const* lessGen = dynamic_cast<EvenLessGenericClass const*>(object); 
    if (lessGen) std::cout << " (value is " << lessGen->value() << ")"; 

    } // for 
    std::cout << std::endl; 

    return 0; 
} // main() 

Sur ma plate-forme, ce code (en C++ 14) émet:

[one] EvenLessGenericClass(1) (value is 1) 
[six] EvenLessGenericClass(6) (value is 6) 
[any] NotTooGenericClass() 

(illustrant également le sens de "non ordonnée" au nom de la carte). Cet exemple a été compilé avec g++ -Wall -pedantic -std=c++14 -o test.exe test.cpp (GCC 6.4.0).

2

En C++ 17 vous pouvez utiliser std :: carte < std :: string, std :: tout >.