我了解多态和泛型如何在其他编程语言(Java,C#,Typescript等)中进行交互。但是在C ++中,感觉像是我想利用的模式失败了。
在此示例中,我想要一个Name
扩展了Word
s的s列表。我想将我的名字列表传递给一个接受单词列表的方法,但是我不能。我可以用我的名字填充单词列表,但是这会丢失类型信息,这意味着我无法调用继承到Name类的任何方法。
#include <iostream>
#include <string>
#include <list>
class Word{
public:
virtual void say() = 0;
};
class Name : public Word{
std::string name;
public:
Name(std::string name){
this-> name = name;
}
void say() override{
std::cout << name << std::endl;
}
void important_name_function(){
// Something very important I want to call
}
};
void say_one(Word* w){
w-> say();
}
void say_all(std::list<Word*> list){
for(Word* w: list){
w-> say();
}
}
int main(){
std::list<Word*> words = {new Name("Kai"), new Name("Ben"), new Name("Sam")};
say_one(words.front()); //Works, due to the magic of polymorphism
say_all(words); //Works, due to the magic of polymorphism
std::list<Name*> names = {new Name("Kai"), new Name("Ben"), new Name("Sam")};
say_one(names.front()); //STILL works due to the magic of polymorphism AND type information is retained
say_all(names); //Fails but feels like it shouldn't
}
例如,在Java中,我可以通过将say all定义为
static <T extends Word> void say_all (java.util.LinkedList<T> list){
for(T w:list){
w.say();
}
}
但是,在C ++中寻找这种解决方案会让我觉得很丑陋(C ++等效于对Java参数/返回类型使用<T extended Class>)
对我来说,这意味着下列条件之一是正确的:
- 我错误地认为它很丑
那。
我发现以下丑陋之处:
template<class T>
void say_all(const std::list<T*>& list) {
for (T* w : list) {
w->say();
}
}
请注意,您不必完全限制T
示例。在Java中无法真正做到这一点。
仅当您实际需要限制T
为的实例时Word
:
template<class T, typename = std::enable_if_t<std::is_base_of<Word, T>::value>>
void say_all(const std::list<T*>& list) {
for (T* w : list) {
w->say();
}
}
或带有概念:
template<typename T>
concept IsWord = std::is_base_of<Word, T>::value;
template<class T> requires IsWord<T>
void say_all(const std::list<T*>& list) {
for(T* w : list) {
w->say();
}
}
旁注:
new
使用操作员并使用std::list<std::unique_ptr<Word>>
和std::make_unique
代替。本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句