Phương pháp tiếp cận của bạn về cơ bản là đi đúng hướng. Bạn sẽ phải biết loại bạn đưa vào. Bạn có thể sử dụng boost::any
và bạn sẽ có thể đặt bất cứ thứ gì vào bản đồ, miễn là bạn biết những gì bạn đưa vào:
std::map<std::string, boost::any> table;
table["hello"] = 10;
std::cout << boost::any_cast<int>(table["hello"]); // outputs 10
Một số câu trả lời khuyến cáo việc sử dụng boost::variant
để giải quyết vấn đề này. Nhưng nó sẽ không cho phép bạn lưu trữ các giá trị được đánh máy tùy ý trong bản đồ (như bạn muốn). Bạn phải biết tập hợp các loại có thể có trước đó. Cho rằng, bạn có thể làm các việc trên dễ dàng hơn:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = 10;
// outputs 10. we don't have to know the type last assigned to the variant
// but the variant keeps track of it internally.
std::cout << table["hello"];
đó làm việc vì boost::variant
quá tải operator<<
cho mục đích đó. Điều quan trọng là phải hiểu rằng nếu bạn muốn lưu những gì hiện đang chứa trong biến thể, bạn vẫn phải biết loại, như với trong trường hợp boost::any
:
typedef boost::variant<int, std::string, void*> variant_type;
std::map<std::string, variant_type> table;
table["hello"] = "bar";
std::string value = boost::get<std::string>(table["hello"]);
Trình tự công việc để một biến thể là một thời gian chạy thuộc tính của luồng điều khiển của mã của bạn, nhưng loại được sử dụng của bất kỳ biến nào được xác định tại thời gian biên dịch. Vì vậy, nếu bạn muốn nhận được giá trị của biến thể, bạn phải biết loại của nó. Cách khác là sử dụng lượt truy cập, như được nêu trong tài liệu biến thể. Nó hoạt động bởi vì các biến thể lưu trữ một mã mà nói với nó mà loại cuối cùng được gán cho nó. Dựa trên đó, nó quyết định khi chạy sự quá tải của khách truy cập mà nó sử dụng. boost::variant
là khá lớn và không hoàn toàn tuân thủ tiêu chuẩn, trong khi boost::any
là tiêu chuẩn tuân thủ nhưng sử dụng bộ nhớ động ngay cả đối với các loại nhỏ (vì vậy nó chậm hơn. Biến thể có thể sử dụng ngăn xếp cho các loại nhỏ). Vì vậy, bạn phải trao đổi những gì bạn sử dụng.
Nếu bạn thực sự muốn đặt các đối tượng vào nó chỉ khác nhau theo cách họ làm điều gì đó, đa hình là một cách tốt hơn để đi. Bạn có thể có một cơ sở đẳng cấp mà bạn lấy được từ:
std::map< std::string, boost::shared_ptr<Base> > table;
table["hello"] = boost::shared_ptr<Base>(new Apple(...));
table["hello"]->print();
Mà về cơ bản sẽ yêu cầu bố trí lớp này:
class Base {
public:
virtual ~Base() { }
// derived classes implement this:
virtual void print() = 0;
};
class Apple : public Base {
public:
virtual void print() {
// print us out.
}
};
Các boost::shared_ptr
là một cái gọi là con trỏ thông minh. Nó sẽ tự động xóa các đối tượng của bạn nếu bạn xóa chúng ra khỏi bản đồ của bạn và không có gì khác là tham chiếu chúng với chúng nữa. Về lý thuyết, bạn có thể đã làm việc với một con trỏ đơn giản, nhưng sử dụng một con trỏ thông minh sẽ làm tăng đáng kể sự an toàn.Đọc hướng dẫn shared_ptr tôi liên kết đến.
BTW, std :: bản đồ không phải là bảng băm; nó thường được thực hiện như một cây màu đỏ-đen, nhưng trong mọi trường hợp, các phím được giữ theo thứ tự. Có std :: tr1 :: unordered_map, thường được thực hiện như một bảng băm. –
Chris, cảm ơn vì đã chỉ ra điều đó. Tôi bây giờ gọi nó là một "mảng kết hợp". –
liên quan: ["điểm của mảng dị thể là gì?"] (Http://stackoverflow.com/questions/4534612/what-is-the-point-of-heterogenous-arrays) –