2017-08-17 15 views
5

Trong Java, bạn có thể tạo một Ánh xạ ánh xạ các kiểu đối tượng String tới Generic có thể được đúc một cách rõ ràng đến các lớp khác. Có cách nào tốt đẹp để bắt chước chức năng này trong C++?C++ Tương đương với Bản đồ Java <String, Object>

+0

Có bản đồ trong C++ 11/14, std :: map. xin vui lòng kiểm tra xem nó có thể đáp ứng yêu cầu của bạn. – tibetty

+0

và cũng ['std :: unordered_map'] (http://en.cppreference.com/w/cpp/container/unordered_map) –

+1

tôi nghĩ rằng op đang nói về một đối tượng lớp có thể chấp nhận bất kỳ loại đối tượng nào ... không phải về bộ sưu tập vùng chứa dữ liệu Bản đồ –

Trả lời

1

Là ngôn ngữ được nhập khá mạnh, C++ không có "Loại đối tượng chung". Nó chắc chắn có các thùng chứa liên kết: std::map (một hương vị của cây nhị phân) và std::unordered_map (một hương vị của bảng băm). Điều nào tốt hơn tùy thuộc vào trường hợp sử dụng và thường không thể được quyết định mà không có hồ sơ.

Điều gần nhất với đối tượng chung mà tôi có thể nghĩ là một tổ tiên chung cho tất cả các đối tượng có thể được đặt trong bản đồ này. Ở đây, ý tưởng là tạo ra một hệ thống phân cấp lớp với đa hình động và lưu trữ các đối tượng trong bản đồ dưới dạng con trỏ được đúc vào tổ tiên chung đó. Thiết kế lý tưởng sẽ làm cho việc đúc các vật thể này trở về lớp dẫn xuất của chúng không cần thiết. Nếu thay vào đó, bạn cần phải sử dụng dynamic_cast (và có thể kiểm tra xem nó có thành công hay không).

Bắt buộc phải lưu con trỏ vào các đối tượng trên bản đồ, chứ không phải chính đối tượng. Nếu không, đối tượng cố gắng chèn vào bản đồ, chỉ có phần tổ tiên chung sẽ được lưu trữ và tính đa hình sẽ bị mất. Nó cũng cần phải được quyết định xem bản đồ sở hữu các đối tượng hay không (không có bộ sưu tập rác ở đây). Nếu không, con trỏ đơn giản có thể hoạt động. Nếu bản đồ sở hữu các đối tượng, tôi khuyên bạn nên lưu trữ chúng trong "con trỏ duy nhất" (std::unique_ptr). Wrapping lên:

#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() 

Trên nền tảng của tôi, mã này (sử dụng C++ 14) phát ra:

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

(cũng minh họa ý nghĩa của "thứ tự" trong tên bản đồ). Ví dụ này được biên dịch với g++ -Wall -pedantic -std=c++14 -o test.exe test.cpp (GCC 6.4.0).

2

Trong C++ 17, bạn có thể sử dụng std :: map < std :: string, std :: any >.

Các vấn đề liên quan