【问题标题】:C++ Calling a virtual method from a multiply inherited template classC++ 从多重继承的模板类调用虚方法
【发布时间】:2014-12-08 17:23:39
【问题描述】:

我这里有很多代码,但恐怕这是我可以用来表达问题的尽可能少的代码,所以请多多包涵:

#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);
}

问题出在这行:

eat(*pCastFruit);

我收到以下错误:

  • 错误 C2385:“吃”的访问不明确
  • 错误 C3861:“吃”:找不到标识符

我尝试将行替换为:

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

错误现在更改为:

  • 错误 LNK2019:无法解析的外部符号“受保护:虚拟 void __thiscall FruitEater::eat(class Apple const &)" (?eat@?$FruitEater@VApple@@@@MAEXABVApple@@@Z) 在函数中引用 “私有:bool __thiscall MultiFruitEater::dispatchEatByType(class Fruit const &)” (??$dispatchEatByType@VApple@@VOrange@@VBanana@@@?$MultiFruitEater@VApple@@VOrange@@VBanana@@@@AAE_NABVFruit@@@Z)

  • 错误 LNK2019:无法解析的外部符号“受保护:虚拟 void __thiscall FruitEater::eat(class Banana const &)" (?eat@?$FruitEater@VBanana@@@@MAEXABVBanana@@@Z) 函数“私有:bool __thiscall MultiFruitEater::dispatchEatByType(水果类 常量 &)" (??$dispatchEatByType@VBanana@@@?$MultiFruitEater@VApple@@VOrange@@VBanana@@@@AAE_NABVFruit@@@Z)

有什么想法吗?

【问题讨论】:

  • 如果您将对eat() 的调用更改为:FruitEater&lt;First&gt; &amp;fe = *this; fe.eat(*pCastFruit);,会发生什么情况? (您需要更改代码以允许访问该方法。)
  • 我得到了关于为什么会发生这种情况的澄清。见this question

标签: c++ templates multiple-inheritance variadic-templates


【解决方案1】:

分辨率:

所以我得到了你的回复:

使用您定义的 ASSISTANCE :(当您判断您现在发送的类型不是 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)

在你的fruitEater 类中:(它让你的multieater 访问eat 方法

template<typename FruitType>
class FruitEater {

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

};

如何使用新的 ASSISTANCE 定义:

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

解释:(没有我想要的那么精确)

我认为这样做的问题 (this-&gt;FruitEater&lt;First&gt;::eat(*pCastFruit);) 是您强制编译器使用 FruitEater::eat() 方法,这是一个虚拟 void...

【讨论】:

  • 这工作除了现在,正如 jxh 所说,我们正在访问一个据称不同的对象上的吃(一种受保护的方法),所以我们被拒绝访问。通过将 MultiFruitEater 设为 FruitEater 的朋友来解决。
  • @saarraz1 不是我做的吗?我没明白你的意思
  • 这完美解决了问题,只是又引入了一个小错误(你的解决方案没有问题,别担心(:)
  • 大声笑,谢谢,错误(正如我在第一条评论中所说)是我们无法访问 eat 方法,因为它是受保护的,我们通过不是 this 的指针访问它。我通过让 MultiFruitEater 成为 FruitEater 的朋友来解决这个问题。
猜你喜欢
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-18
  • 1970-01-01
  • 1970-01-01
  • 2017-03-31
相关资源
最近更新 更多