无重复代码的多态函数调用

Polymorphic function call without duplicate code

本文关键字:多态 函数调用 代码      更新时间:2023-10-16

假设一个层次结构的所有类都实现了一个模板成员函数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中的多态调用仍按预期工作(即产生输出"in B")?

请注意,ABCf1f2的实现是不相同的。让我们将其限制为f1s。一个调用名为::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) { /*...*/ }
};

您只需考虑模板函数使用的类特定内容,例如(在您的示例中)类名:

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