首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在多态函数对象中使用std::generate/generate_n?

如何在多态函数对象中使用std::generate/generate_n?
EN

Stack Overflow用户
提问于 2011-02-16 07:37:39
回答 5查看 1.8K关注 0票数 1

我是std::generate的新手,我曾经尝试过构建一个使用它来初始化向量的程序。然而,它的表现与我的预期不同。

我有一个抽象基类:

代码语言:javascript
复制
template <typename G>
class RandomAllele {
 public:
  RandomAllele() { /* empty */ }
  virtual ~RandomAllele() { /* empty */ }

  virtual G operator()() const = 0;
}; 

它被扩展为(例如):

代码语言:javascript
复制
class RandomInt : public RandomAllele<int> {
 public:
  RandomInt(int max) : max_(max) {}
  int operator()() const { return rand() % max_; }
 private:
  int max_;
};

我通过指针将继承类的实例传递给工厂类,然后将其用作std::generate的第三个参数:

代码语言:javascript
复制
template<typename G, typename F>
class IndividualFactory {
 public:
  IndividualFactory(int length, const RandomAllele<G> *random_allele)
      : length_(length), random_allele_(random_allele) { /* empty */ }

  individual_type *generate_random() const {
    std::vector<G> *chromosome = new std::vector<G>(length_);
    std::generate(chromosome->begin(), chromosome->end(), *random_allele_); */

    return new individual_type(chromosome);
  }
 private:
  int length_;
  RandomAllele<G> *random_allele_;
};

现在我得到一个错误,说RandomAllele不能被实例化,因为它是一个抽象类。当指针已经存在时,为什么generate需要实例化它呢?为什么要尝试使用基类而不是继承类RandomInt呢?

如果我将std::generate替换为:

代码语言:javascript
复制
for(auto iter = chromosome->begin(); iter != chromosome->end(); ++iter)
  *iter = (*random_allele_)();

但我仍然希望了解它为什么表现得很奇怪,如果有办法的话,我更喜欢使用generate。

耽误您时间,实在对不起,

Rhys

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-02-16 07:54:51

正如其他人在上面提到的,generategenerate_n函数通过值获取它们的生成器对象,从而使您无法在此上下文中直接使用继承。

然而,您可以做的一个技巧是应用软件工程的基本定理:

任何问题都可以通过添加另一个间接层来解决

而不是直接传递多态函数,而是传递一个包装器函数,该函数存储指向这个多态函数的指针,然后适当地转发调用。例如:

代码语言:javascript
复制
template <typename T> class IndirectFunctor {
public:
    explicit IndirectFunctor(RandomAllele<T>* f) : functor(f) {
         // Handled in initializer list
    }

    T operator() () const {
        return (*functor)();
    }

private:
    RandomAllele<T>* functor;
};

如果您随后将此对象传递给generate,如下所示:

代码语言:javascript
复制
RandomAllele<T>* functor = /* ... create an allele ... */
std::generate(begin, end, IndirectFunctor<T>(functor));

然后,一切都将按预期进行。这样做的原因是,如果按值复制IndirectFunctor<T>,则只需浅层复制存储的指针,该指针仍将指向您想要调用的RandomAllele。这避免了您遇到的切片问题,因为它从不尝试通过基类指针直接复制RandomAllele类型的对象。它总是复制包装器对象,而包装器对象从不尝试复制RandomAllele

希望这能有所帮助!

票数 4
EN

Stack Overflow用户

发布于 2011-02-16 07:44:13

generate的生成器是通过值传递的,因此会被复制。

票数 2
EN

Stack Overflow用户

发布于 2011-02-16 07:48:00

通常,C++标准库实现静态多态性(模板),并且不支持函数对象的运行时多态性(虚方法)。这是因为它通过值传递所有函数对象,假设它们是无状态的或几乎无状态的,这样添加的通过指针或引用传递的间接性将比通过值传递的开销更大。

因为它是通过值传递的,所以这会导致切片,当您尝试使用RandomAllele<G>时,它会认为您指的是确切的类,而不是它实际指向的任何派生类型。不需要在G上模板化,只需直接在确切的生成器函数器类型上模板化即可。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5010807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档