如何实现“虚拟模板功能”?在C ++中 [英] How to achieve "virtual template function" in C++

查看:78
本文介绍了如何实现“虚拟模板功能”?在C ++中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我已经阅读并且我现在知道在C ++中还不能(但是?)虚拟模板成员函数。一种解决方法是使该类成为模板,然后在成员函数中也使用模板参数。

first off: I have read and I know now that a virtual template member function is not (yet?) possible in C++. A workaround would be to make the class a template and then use the template-argument also in the member-function.

但是在OOP的上下文中,我发现如果该类实际上是模板,则以下示例不是很自然。请注意,该代码实际上不起作用,但是gcc-4.3.4报告:错误:模板可能不是虚拟

But in the context of OOP, I find that the below example would not be very "natural" if the class was actually a template. Please note that the code is actually not working, but the gcc-4.3.4 reports: error: templates may not be ‘virtual’

#include <iostream>
#include <vector>

class Animal {
    public:
        template< class AMOUNT >
        virtual void eat( AMOUNT amount ) const { 
            std::cout << "I eat like a generic Animal." << std::endl; 
        }
        virtual ~Animal() { 
        }
};

class Wolf : public Animal {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a wolf!" << std::endl; 
        }
        virtual ~Wolf() { 
        }
};

class Fish : public Animal {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a fish!" << std::endl; 
        }
        virtual ~Fish() { 
        }
};

class GoldFish : public Fish {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a goldfish!" << std::endl; 
        }
        virtual ~GoldFish() { 
        }
};

class OtherAnimal : public Animal {
        virtual ~OtherAnimal() { 
        }
};

int main() {
    std::vector<Animal*> animals;
    animals.push_back(new Animal());
    animals.push_back(new Wolf());
    animals.push_back(new Fish());
    animals.push_back(new GoldFish());
    animals.push_back(new OtherAnimal());

    for (std::vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
        (*it)->eat();
        delete *it;
    }

    return 0;
}

因此,创建 Fish foo有点奇怪。但是,对我来说,为每只动物提供任意数量的食物似乎是可取的。

So creating a "Fish< Amount > foo" is kind of strange. However, it seems desirable to me to provide an arbitrary amount of food to eat for each animal.

因此,我正在寻找有关实现类似目标的解决方案

Thus, I am searching a solution about how to achieve something like

Fish bar;
bar.eat( SomeAmount food );

这在查看for循环时特别有用。一个人可能想给所有不同的动物喂一定量的食物(例如FoodAmount)(例如通过eat()和bind1st()),这很难做到,尽管我很伤脑筋(因此一定程度上)尽管有些人可能现在想争论这是由于向量的统一字符引起的,但我认为/希望有可能实现这一点,我真的很想知道如何做,因为这是现在困扰了我一段时间...

This becomes particularly useful when looking at the for-loop. One might like to feed a specific amount (FoodAmount) to all of the different animals (via eat() and bind1st() e.g.), it could not be done that easily, although I wound find this very inuitive (and thus to some extent "natural). While some might want to argue now that this is due to the "uniform"-character of a vector, I think/wish that it should be possible to achieve this and I really would like to know how, as this is puzzling me for quite some time now...

为了阐明问题的动机,我想对一个Exporter类进行编程,并从中派生出更多的更专业的类,虽然顶层Exporter类通常仅用于装饰/结构目的,但GraphExporter类却是派生类,它应该再次用作更特殊化导出的基类。但是,类似于Animal-example,我希望即使在特殊/派生类上也可以定义GraphExporter *(例如SpecialGraphExplorer),但在调用 write(out_file)时,应为SpecialGraphExporter而不是GraphExporter :: write(out_file)调用适当的成员函数。

To perhaps clarify the motivation behind my question, I want to program an Exporter-class and let different, more specialized classes derive from it. While the top-level Exporter-class is generally only for cosmetic/structural purpose, a GraphExporter-class is derived, that should again serve as a base-class for even more specialzed export. However, similar to the Animal-example, I would like to be able to define GraphExporter* even on specialized/derived classes (e.g. on SpecialGraphExplorer) but when calling "write( out_file )", it should call the appropriate member function for SpecialGraphExporter instead of GraphExporter::write( out_file).

也许这使我情况和意图更加清晰。

Maybe this makes my situation and intentions clearer.

最好,

阴影

推荐答案

经过一番思考,我认为这是经典的多方法要求,即一种基于运行时类型进行调度的方法>个以上的参数。比较而言,通常的虚拟函数是单个调度(它们以 this 类型调度

After some thinking I recognized this as the classic multi-method requirement, i.e. a method that dispatches based on the runtime type of more than one parameter. Usual virtual functions are single dispatch in comparison (and they dispatch on the type of this only).

请参阅以下内容:


  • Andrei Alexandrescu已写过( C ++的精髓之处?)有关在现代C ++设计中使用泛型实现多方法的说明


    • 第11章:多方法 -它实现了基本的多方法,使它们成为对数形式(使用有序类型列表),然后一直到恒定时间的多种方法。相当强大的东西!

    • Andrei Alexandrescu has written (the seminal bits for C++?) on implementing multi-methods using generics in 'Modern C++ design'
      • Chapter 11: "Multimethods" - it implements basic multi-methods, making them logarithmic (using ordered typelists) and then going all the way to constant-time multi-methods. Quite powerful stuff !

      • 不使用任何类型的类型转换(动态,静态,重新解释,const或C样式)

      • 不使用RTTI;

      • 不使用预处理程序;

      • 强类型安全性;

      • 单独编译;

      • 恒定的多方法执行时间;

      • 在多方法调用期间没有动态内存分配(通过new或malloc);

      • 不使用非标准库;

      • 仅使用标准的C ++功能。

      • no use of type casts of any kind (dynamic, static, reinterpret, const or C-style)
      • no use of RTTI;
      • no use of preprocessor;
      • strong type safety;
      • separate compilation;
      • constant time of multimethod execution;
      • no dynamic memory allocation (via new or malloc) during multimethod call;
      • no use of nonstandard libraries;
      • only standard C++ features is used.

      以下是维基百科文章中的简单方法,以供参考(越简单的方法越适合于大量派生类型的缩放) :

      Here is the 'simple' approach from the wikipedia article for reference (the less simple approach scales better for larger number of derived types):

      // Example using run time type comparison via dynamic_cast
      
      struct Thing {
          virtual void collideWith(Thing& other) = 0;
      }
      
      struct Asteroid : Thing {
          void collideWith(Thing& other) {
              // dynamic_cast to a pointer type returns NULL if the cast fails
              // (dynamic_cast to a reference type would throw an exception on failure)
              if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
                  // handle Asteroid-Asteroid collision
              } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
                  // handle Asteroid-Spaceship collision
              } else {
                  // default collision handling here
              }
          }
      }
      
      struct Spaceship : Thing {
          void collideWith(Thing& other) {
              if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
                  // handle Spaceship-Asteroid collision
              } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
                  // handle Spaceship-Spaceship collision
              } else {
                  // default collision handling here
              }
          }
      }
      

      这篇关于如何实现“虚拟模板功能”?在C ++中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆