避免无休止的虚拟查询

时间:2015-08-22 06:50:32

标签: c++ function templates virtual

考虑以下代码:

#include <iostream>
#include <string>

class Base {
protected:
    virtual std::string addMoreDetail (std::string&) const = 0;
};

template <int...> class Derived;

template <>
class Derived<0, 0> : private Base {
private:
    bool b;
protected:
    virtual std::string description() const {return "Whatever1";}
    std::string finalize (std::string& str) const {return b ? addMoreDetail(str) : str;}
};

template <>
class Derived<1, 0> : private Base {
protected:
    virtual std::string description() const {return "Whatever2";}
    std::string finalize (std::string& str) const {return addMoreDetail(str);}
};

template <int N>
class Derived<N, 0, 0> : public Derived<N, 0> {
public:
    virtual std::string description() const override {
        std::string str = Derived<N, 0>::description();   return this->finalize(str);
        // Can this be moved up somehow?
    }
private:
    inline std::string addMoreDetail (std::string& s) const {return s + " Detail1";}
};

template <int N>
class Derived<N, 0, 1> : public Derived<N, 0> {
public:
    virtual std::string description() const override {
        std::string str = Derived<N, 0>::description();   return this->finalize(str);
        // Can this be moved up somehow?
    }
private:
    inline std::string addMoreDetail (std::string& s) const {return s + " Detail2";}
};

int main() {
    std::cout << Derived<0, 0, 0>().description() << '\n';  // Whatever1
    std::cout << Derived<0, 0, 1>().description() << '\n';  // Whatever1
    std::cout << Derived<1, 0, 0>().description() << '\n';  // Whatever2 Detail1
    std::cout << Derived<1, 0, 1>().description() << '\n';  // Whatever2 Detail2
}

我的目标很简单。我想避免写作

std::string str = Derived<N, 0>::description();   return this->finalize(str);

在层次结构中向上移动两次。

这是我的临时解决方案:

#include <iostream>
#include <string>

template <int...> class Derived;

class Base {
protected:
    virtual std::string description() const = 0;
    virtual std::string addMoreDetail (std::string&) const = 0;
    template <int N> std::string descriptionBase (const Derived<N, 0>* derived) const {
//  std::string str = derived->description();   return derived->finalize(str);  // Endless look-up!
        std::string str = derived->staticDescription();   return derived->finalize(str);
    }
};

template <>
class Derived<0, 0> : protected Base {
private:
    bool b;
    friend Base;
protected:
    virtual std::string description() const {return staticDescription();}
    static std::string staticDescription() {return "Whatever1";}
    std::string finalize (std::string& str) const {return b ? addMoreDetail(str) : str;}
};

template <>
class Derived<1, 0> : protected Base {
    friend Base;
protected:
    virtual std::string description() const {return staticDescription();}
    static std::string staticDescription() {return "Whatever2";}
    std::string finalize (std::string& str) const {return addMoreDetail(str);}
};

template <int N>
class Derived<N, 0, 0> : public Derived<N, 0> {
public:
    std::string description() const override {return this->template descriptionBase<N>(this);}
private:
    inline std::string addMoreDetail (std::string& s) const {return s + " Detail1";}
};

template <int N>
class Derived<N, 0, 1> : public Derived<N, 0> {
public:
    std::string description() const override {return this->template descriptionBase<N>(this);}
private:
    inline std::string addMoreDetail (std::string& s) const {return s + " Detail2";}
};

int main() {
    std::cout << Derived<0, 0, 0>().description() << '\n';  // Whatever1
    std::cout << Derived<0, 0, 1>().description() << '\n';  // Whatever1
    std::cout << Derived<1, 0, 0>().description() << '\n';  // Whatever2 Detail1
    std::cout << Derived<1, 0, 1>().description() << '\n';  // Whatever2 Detail2
}

但是这在我的程序中实际上并不起作用,因为description()不是静态的,因为它依赖于数据成员。但是,如果我使用

std::string str = derived->description();   return derived->finalize(str);

而不是

std::string str = derived->staticDescription();   return derived->finalize(str);

我得到了一个无休止的运行时虚拟查找,因为它不断回到原始状态。怎么避免这个?或者有更好的方法来实现我的目标吗?

1 个答案:

答案 0 :(得分:1)

使您的staticDescription方法成为非虚拟非静态成员函数,即保持代码不变,并在定义static方法时删除staticDescription。您可能希望将staticDescription重命名为doGetDescription左右。

通常的解决方案可能是使用模板方法模式(或非虚拟接口模式):

class BaseClass {
public:
   std::string getDescription () const {
      return this->doGetDescription ();
   }

private:
   virtual std::string doGetDescription () const = 0;
};

class FirstDerived : public BaseClass {
   std::string doGetDescription () const override { return "First"; }
};

class SecondDerived : public BaseClass {
   std::string doGetDescription () const override { return "Second"; }
};

BaseClass & b = SecondDerived {};
std::cout << b.getDescription () << std::endl;