C ++泛型和多态性:这种模式可行吗?

凯鲑鱼

我了解多态和泛型如何在其他编程语言(Java,C#,Typescript等)中进行交互。但是在C ++中,感觉像是我想利用的模式失败了。

在此示例中,我想要一个Name扩展了Wordss列表我想将我的名字列表传递给一个接受单词列表的方法,但是我不能。我可以我的名字填充单词列表,但是这会丢失类型信息,这意味着我无法调用继承到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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章