[英]Sets (arrays of heterogeneous types) in C++
我想用 C++ 模擬 python 集。 根據faq ,一種慣用的方法是使用std::vector
將指針(如果智能指針更好)存儲到句柄類,然后由我們想要存儲在模擬中的特定類型重載放。
這是我的嘗試:
// experimenting with vectors of heterogeneous elements (like sets in python)
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// Handle can wrap an int, a double, or a string.
class Handle {
public:
Handle();
virtual int val();
virtual double val();
virtual std::string val();
};
class Int : public Handle {
public:
Int(const int n) : value(n) {};
int val() override { return value; };
private:
int value;
};
class Double : public Handle {
public:
Double(const double n) : value(n) {};
double val() override { return value; };
private:
double value;
};
class String : public Handle {
public:
String(const std::string& n) : value(n) {};
std::string val() override { return value; };
private:
std::string value;
};
int main() {
// v simulates a set with 12 elements of types int, double, or string.
std::vector<std::shared_ptr<Handle>> v(12);
for (int i = 0; i < v.size(); i += 3) {
v[i] = std::shared_ptr<Int>(new Int(i));
v[i + 1] = std::shared_ptr<Double>(new Double(i + 1.));
v[i + 2] = std::shared_ptr<String>(new String(std::to_string(i + 2)));
}
for (auto& it : v) {
std::cout << it->val() << std::endl;
}
}
這種方法比將v
聲明為std::vector<Handle*>
更可取,因為使用智能指針可以讓我忘記手動刪除指針,同時實現運行時多態性。
但是上面的代碼不能編譯,因為我們不允許只在返回類型上重載函數(在這種情況下是val()
)。
有沒有辦法修復我的代碼,以便我可以模擬具有不同類型的集合? 有沒有更好的,慣用的方法來做到這一點?
這是我在 n 之后更改代碼的方式。 '代詞' m. 的回答。 代碼似乎有效,我很高興將它作為使用繼承和智能指針的練習(即使它不是手頭特定問題的最佳解決方案,請參閱 Maxim Egorushkin 的答案以獲得更好的方法)。
// experimenting with vectors of heterogeneous elements (like sets in python)
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// Handle can wrap an int, a double, or a string.
class Handle {
public:
Handle() {};
virtual void print(std::ostream&) = 0;
};
class Int : public Handle {
public:
Int(const int n) : value(n) {};
void print(std::ostream& s) override { s << value << std::endl; };
private:
int value;
};
class Double : public Handle {
public:
Double(const double n) : value(n) {};
void print(std::ostream& s) override { s << value << std::endl; };
private:
double value;
};
class String : public Handle {
public:
String(const std::string& n) : value(n) {};
void print(std::ostream& s) override { s << value << std::endl; };
private:
std::string value;
};
int main() {
std::vector<std::shared_ptr<Handle>> v(12);
for (size_t i = 0; i < v.size(); i += 3) {
v[i] = std::shared_ptr<Int>(new Int(i));
v[i + 1] = std::shared_ptr<Double>(new Double(i + 1.));
v[i + 2] = std::shared_ptr<String>(new String(std::to_string(i + 2)));
}
for (const auto& it : v) {
it->print(std::cout);
}
}
我想用 C++ 模擬 python 集。 根據常見問題解答,一種慣用的方法是使用存儲指針的
std::vector
......
C++ 中的std::set
是std::set
(通常是紅黑樹)和std::unordered_set
(哈希表)。 std::vector
是一個可調整大小的數組。
如果您知道要存儲在集合中的所有類型,請使用std::variant
作為值,而不是指針。
例如:
#include <unordered_set>
#include <variant>
#include <string>
int main() {
using Value = std::variant<int, double, std::string>;
using ValueSet = std::unordered_set<Value>;
ValueSet s;
s.insert(1); // int
s.insert(3.14); // double
s.insert("hello"); // string
for(auto const& value : s)
visit([](auto&& v) { std::cout << v << '\n'; }, value);
}
C++ 是一種靜態類型語言。 每個表達式都有一個靜態確定的類型。 這意味着您、tge 編譯器和其他所有人都可以僅從程序文本中確定類型,而無需嘗試執行任何代碼。
(由 tge 表達式表示的對象也可能具有動態類型,在運行時確定,但這不是我們所關心的)。 一種
我們來看看這個表達。
it->val()
它的類型是什么?
唯一可能的答案是std::string
。 事實上, it
的類型是std::shared_ptr<Handle>
,並且Handle::val
被指定為返回std::string
。 Handle
具有派生類型這一事實Handle
。 無論指向對象的動態類型是什么, it->val()
的靜態類型是std::string
,如果某事物具有std::string
靜態類型,則它不能具有動態類型,例如double
。 這就是您不能以這種方式覆蓋val
的原因。
那么如果我們想根據對象的動態類型打印不同的東西該怎么辦呢?
標准的 OOP 解決方案是有一個打印的方法,與返回要打印的東西的方法相反。 在 C++ 術語中,這將是一個虛函數,例如
virtual void print() = 0;
在每個派生類中重寫。
當然,現實生活並沒有那么簡單。 如果我們需要打印到任意流怎么辦? 我們需要將流作為參數傳遞給print
。 也許我們需要傳遞更多的東西。 也許我們想指定打印字段的寬度、精度或其他任何內容。 如果我們除了打印之外還想做一堆其他的事情怎么辦? 對於我們想做的每件事,我們是否需要一個單獨的方法? OOP 研究這些和更多問題的答案,但我無法在一個 SO 帖子中回答它們:(
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.