从一组基类指针调用非虚拟成员函数?

时间:2014-06-16 23:57:00

标签: c++ templates

我有一个班级D,我想让班级A,B,C继承。但是,我想要声明为pure virtual的函数是模板化的。

不幸的是,用visual studio的话说:

member function templates cannot be virtual

A,B,C以完全相同的方式调用成员运算符,但是可以返回不同的值(doubleunsigned int。但是我很乐意让它工作只有double):

template<typename T>
double operator()(T&, unsigned int b){/*code*/};

我怎样才能正确地创建类A,B,C的多态集合(类似于std::vector<D*>,如果我不想要成员函数模板那就可以工作),这样做我正在尝试做什么?

编辑:

我希望能够做的一个例子:

std::default_random_engine rng((unsigned int) std::time(0));
std::vector<D*> v;
v.push_back(new A(0.3));
v.push_back(new B(1.0,3.2));
v.push_back(new C);

for(auto x : v){
    for(auto y : x->operator()(rng,5){
        std::cout << y << ',';
    }
    std::cout << std::endl;
}

4 个答案:

答案 0 :(得分:2)

我不完全确定你想要做什么,但是如果你将模板定义移到类而不是方法上,一切都很愉快。这样做你想要的吗?

template<typename T>
class A
{
public :
    virtual double operator() (T& t, unsigned int b) = 0;
};

template<typename T>
class B : public A<T>
{
public:
    virtual double operator() (T& t, unsigned int b)
    {
         // code
    }
};

编辑:

或者,鉴于您不希望在类级别使用模板,那么将随机计算从多态方法中移出,然后对实际的硬件部分使用简单的plymorphic方法。这假设您只想生成一个随机数,如果您想要更多,您可以随时创建一个随机数的向量,其大小在构造中确定。无论如何,下面的代码演示了我在说什么:

class D
{
public :
    template<typename T>
    double operator() (T& t, unsigned int b)
    {
        double calc_rand = t();
        return DoStuff(calc_rand, b);
    }

protected :
    virtual double DoStuff(double rnd_value, unsigned int b) = 0;
};

class A : public D
{
protected :

    virtual double DoStuff(double rnd_value, unsigned int b)
    {
        return rnd_value * b;
    }
};

int main(void)
{
    std::random_device rd;
    A a;
    std::cout << a(rd, 5) << std::endl;
}

答案 1 :(得分:0)

你很可能需要在这里使用delegates。如果所有类都具有相同的名称和参数,那么就像执行操作一样简单:

template <typename T>
class baseWrapper{
    double method(T& a, unsigned int b) = 0;
};

template <typename T, typename myClass>
class wrapper: public baseWrapper<T>{
   myClass &instance;
   double method(T& a, unsigned int b){
      return instance.method<T>(a,b);
   };

   wrapper(myClass &instance){this->instance = instance;};
};

然后你可以创建一个代表集合:

std::vector<baseWrapper<int>*> vec;
A myObject1, B myObject2;    

wrapper<int,A> wrapper1(myObject1);
wrapper<int,B> wrapper2(myObject2);

vec.push_back(&wrapper1);
vec.push_back(&wrapper2);

如果函数的命名方式不同,则需要将函数指针作为附加参数传递,或者使用SFINAE进行测试。

答案 2 :(得分:0)

您不应该使用模板函数,只需通过虚函数将委托传递给rng。所以基本上你可以这样做:

class D
{
  virtual double operator()(std::function<int()>, int)=0;
};

并称之为:

std::default_random_engine rng;
std::vector<D*> v;
...
for(auto x : v)
{
  std::cout << x->operator(std::bind(rng), 5) << ',';
}

答案 3 :(得分:0)

也许您可以为成员函数的模板参数实现类型擦除。按照您的RNG示例:

class RandUIntIfc {
public:
    virtual ~RandUIntIfc() = 0;
    virtual unsigned int min() const = 0;
    virtual unsigned int max() const = 0;
    virtual unsigned int operator()() = 0;
};

class RandUInt {
public:
    template <typename RNG>
    explicit RandUInt(RNG& rng);
    unsigned int min() const;
    unsigned int max() const;
    unsigned int operator()();

private:
    std::shared_ptr<RandUIntIfc> impl_;

    template <typename RNG>
    class Impl : public RandUIntIfc {
    public:
        explicit Impl(RNG& rng);
        virtual unsigned int min() const;
        virtual unsigned int max() const;
        virtual unsigned int operator()();
    private:
        RNG& ref_;
    };
};

我希望所有实际的成员定义都很明显。只留下D的更改和使用它的代码:

class D {
public:
    virtual ~D() = 0;
    virtual double operator()(RandUInt rng, unsigned int b) = 0;
};

std::default_random_engine rng((unsigned int) std::time(0));
RandUInt typeless_rng(rng);
std::vector<D*> v;
// ...

for(auto x : v){
    for(auto y : x->operator()(typeless_rng,5){
        std::cout << y << ',';
    }
    std::cout << std::endl;
}