多态函数调用没有重复代码

时间:2016-03-25 12:46:33

标签: c++ polymorphism

假设层次结构的所有类都实现了模板成员函数g。所有类共享调用此模板的另外两个函数f1f2的相同实现:

struct A {
    virtual void f1() {
        g(5);
    }
    virtual void f2() {
        g(5.5);
    }
private:
    template <typename T> void g(T) {std::cout << "In A" << std::endl;}
};

struct B: A {
    // Can I get rid of this duplicate code?
    virtual void f1() {
        g(5);
    }
    virtual void f2() {
        g(5.5);
    }
private:
    template <typename T> void g(T) {std::cout << "In B" << std::endl;}
};

struct C: A {
    // Can I get rid of this duplicate code?
    virtual void f1() {
        g(5);
    }
    virtual void f2() {
        g(5.5);
    }
private:
    template <typename T> void g(T) {std::cout << "In C" << std::endl;}
};

int main()
{
    B b;
    A &a = b;
    a.f1();
    return 0;
}

由于f1f2的实现在所有类中都是相同的,我如何摆脱重复的代码,并且main中的多态调用仍然按预期工作(即产生输出“在B中”?

2 个答案:

答案 0 :(得分:3)

请注意f1f2ABC的实现 不相同。我们将其限制为f1 s。一个调用名为::A::g<int>的函数,另一个调用名为::B::g<int>的函数,第三个调用名为::C::g<int>的函数。他们很远相同。

你能做的最好的就是CRTP式的基础:

template <class Derived>
struct DelegateToG : public A
{
  void f1() override
  {
    static_cast<Derived*>(this)->g(5);
  }

  void f2() override
  {
    static_cast<Derived*>(this)->g(5.5);
  }
};

class B : public DelegateToG<B>
{
  friend DelegateToG<B>;
private:
  template <class T> void g(T) { /*...*/ }
};

class C : public DelegateToG<C>
{
  friend DelegateToG<C>;
private:
  template <class T> void g(T) { /*...*/ }
};

答案 1 :(得分:1)

您可以将模板函数使用的类特定事物分解出来,例如(在您的示例中)类名:

#include <iostream>
using namespace std;

class A
{
private:
    virtual auto classname() const -> char const* { return "A"; }

protected:
    template <typename T> void g(T) {cout << "In " << classname() << endl;}

public:
    virtual void f1() { g(5); }
    virtual void f2() { g(5.5); }
};

class B
    : public A
{
private:
    auto classname() const -> char const* override { return "B"; }
};

class C
    : public A
{
private:
    auto classname() const -> char const* override { return "C"; }
};

auto main()
    -> int
{ static_cast<A&&>( B() ).f1(); }