C++ Calling a virtual method from a multiply inherited template class

社会主义新天地 提交于 2020-01-06 19:28:56

问题


I have a lot of code here but I'm afraid this is as little code as I could put to convey the problem, so please bear with me:

#include <iostream>

#define ASINSTANCE(x, type, y)                                                 \
    type * y = dynamic_cast<type *>(&(x));                                     \
    if (y)

class Fruit {
    virtual void a() = 0; // This is to surpress the "Fruit isn't polymorphic" we'd otherwise get.
};

class Apple : public Fruit {
    virtual void a() {

    }
};

class Orange : public Fruit {
    virtual void a() {

    }
};

class Banana : public Fruit {
    virtual void a() {

    }
};

template<typename FruitType>
class FruitEater {

protected:
    virtual void eat(const FruitType & t) = 0;

};

template<typename... FruitTypes>
class MultiFruitEater : public FruitEater<FruitTypes>... {

public:
    // Eat any fruit if it belongs to FruitTypes (returns false otherwise).
    bool dispatchEat(const Fruit & fruit);

private:
    template<typename First>
    bool dispatchEatByType(const Fruit & fruit);

    template<typename First, typename Second, typename... Rest>
    bool dispatchEatByType(const Fruit & fruit);

};

class MyEater : public MultiFruitEater<Apple, Orange, Banana> {

protected:
    virtual void eat(const Apple & t);
    virtual void eat(const Orange & t);
    virtual void eat(const Banana & t);
};

void MyEater::eat(const Apple & t) {
    std::cout << "Ate apple." << std::endl;
}
void MyEater::eat(const Orange & t) {
    std::cout << "Ate orange." << std::endl;
}
void MyEater::eat(const Banana & t) {
    std::cout << "Ate banana." << std::endl;
}

template<typename... FruitTypes>
bool MultiFruitEater<FruitTypes...>::dispatchEat(const Fruit & fruit) {
    return dispatchEatByType<FruitTypes...>(fruit);
}

template<typename... FruitTypes>
template<typename First>
bool MultiFruitEater<FruitTypes...>::dispatchEatByType(const Fruit & fruit) {
    ASINSTANCE(fruit, const First, pCastFruit) {
        eat(*pCastFruit);
        return true;
    }
    return false;
}

template<typename... FruitTypes>
template<typename First, typename Second, typename... Rest>
bool MultiFruitEater<FruitTypes...>::dispatchEatByType(const Fruit & fruit) {
    ASINSTANCE(fruit, const First, pCastFruit) {
        eat(*pCastFruit);
        return true;
    }
    return dispatchEatByType<Second, Rest...>(fruit);
}

int main() {
    MyEater eater;
    Banana b;
    eater.dispatchEat(b);
}

The problem is with the line:

eat(*pCastFruit);

I'm getting the following errors:

  • error C2385: ambiguous access of 'eat'
  • error C3861: 'eat': identifier not found

I tried replacing the line with:

this->FruitEater<First>::eat(*pCastFruit);

The errors now changed to:

  • error LNK2019: unresolved external symbol "protected: virtual void __thiscall FruitEater::eat(class Apple const &)" (?eat@?$FruitEater@VApple@@@@MAEXABVApple@@@Z) referenced in function "private: bool __thiscall MultiFruitEater::dispatchEatByType(class Fruit const &)" (??$dispatchEatByType@VApple@@VOrange@@VBanana@@@?$MultiFruitEater@VApple@@VOrange@@VBanana@@@@AAE_NABVFruit@@@Z)

  • error LNK2019: unresolved external symbol "protected: virtual void __thiscall FruitEater::eat(class Banana const &)" (?eat@?$FruitEater@VBanana@@@@MAEXABVBanana@@@Z) referenced in function "private: bool __thiscall MultiFruitEater::dispatchEatByType(class Fruit const &)" (??$dispatchEatByType@VBanana@@@?$MultiFruitEater@VApple@@VOrange@@VBanana@@@@AAE_NABVFruit@@@Z)

Any ideas?


回答1:


Resolution:

So I got your reponse:

Using Your define ASSISTANCE : (as you gess the type you now send isn't const

#define ASINSTANCE(x, type, y, eater)                                   \
  const type * y = dynamic_cast<const type *>(&(x));                    \
  FruitEater<type>* eater = dynamic_cast<FruitEater< type >*>(this);    \
  if (y && eater)

In your fruitEater class: (it let your multieater acccess to the eat methode

template<typename FruitType>
class FruitEater {

 protected:
  template<typename... Fruit> friend class MultiFruitEater;
  virtual void eat(const FruitType & t) = 0;

};

How to use your new ASSISTANCE define:

  ASINSTANCE(fruit, First, pCastFruit, eater) {
    eater->eat(*pCastFruit);
    return true;
  }

Explanation: (not as precise as i would want)

I think the problem by doing this (this->FruitEater<First>::eat(*pCastFruit);), is you force the compiler to use the FruitEater::eat() methode, wich is a virtual void...



来源:https://stackoverflow.com/questions/26351963/c-calling-a-virtual-method-from-a-multiply-inherited-template-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!