C++:如何用相同的接口覆盖特定 class 的方法
C++: How to override method of a specific class with same interface
我有一种情况,我需要从两个具有相同接口的 类 继承,但要分别覆盖它们,我绝对不能调整接口。请参阅下面的代码示例
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
struct Derived : public Foo<int>, public Foo<double>
{
#if 0 // having something like this would be great, but unfortunately it doesn't work
void Foo<int>::foo() override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void Foo<double>::foo() override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
#endif
};
您始终可以定义声明自己接口的中间体 类:
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
struct ProxyFooInt : public Foo<int>
{
virtual void fooInt() = 0;
void foo() override
{
return fooInt();
}
};
struct ProxyFooDouble : public Foo<double>
{
virtual void fooDouble() = 0;
void foo() override
{
return fooDouble();
}
};
struct Derived : public ProxyFooInt, public ProxyFooDouble
{
void fooInt() override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void fooDouble() override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};
更高级的解决方案是使用 CRTP:
template<typename D>
struct CrtpFooInt : public Foo<int>
{
void foo() override
{
return static_cast<D*>(this)->fooInt();
}
};
template<typename D>
struct CrtpFooDouble : public Foo<double>
{
void foo() override
{
return static_cast<D*>(this)->fooDouble();
}
};
struct Derived : public CrtpFooInt<Derived>, public CrtpFooDouble<Derived>
{
void fooInt()
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void fooDouble()
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};
解决这个问题的另一种创造性方法是使用添加一些重载的能力来区分 foo()
:
的不同调用
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
template<typename T>
struct Tag{};
template<typename T>
struct Overloader : public Foo<T>
{
virtual void foo(Tag<T>) = 0;
void foo() override
{
foo(Tag<T>{});
}
};
struct Derived : public Overloader<int>, public Overloader<double>
{
void foo(Tag<int>) override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void foo(Tag<double>) override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};
我有一种情况,我需要从两个具有相同接口的 类 继承,但要分别覆盖它们,我绝对不能调整接口。请参阅下面的代码示例
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
struct Derived : public Foo<int>, public Foo<double>
{
#if 0 // having something like this would be great, but unfortunately it doesn't work
void Foo<int>::foo() override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void Foo<double>::foo() override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
#endif
};
您始终可以定义声明自己接口的中间体 类:
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
struct ProxyFooInt : public Foo<int>
{
virtual void fooInt() = 0;
void foo() override
{
return fooInt();
}
};
struct ProxyFooDouble : public Foo<double>
{
virtual void fooDouble() = 0;
void foo() override
{
return fooDouble();
}
};
struct Derived : public ProxyFooInt, public ProxyFooDouble
{
void fooInt() override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void fooDouble() override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};
更高级的解决方案是使用 CRTP:
template<typename D>
struct CrtpFooInt : public Foo<int>
{
void foo() override
{
return static_cast<D*>(this)->fooInt();
}
};
template<typename D>
struct CrtpFooDouble : public Foo<double>
{
void foo() override
{
return static_cast<D*>(this)->fooDouble();
}
};
struct Derived : public CrtpFooInt<Derived>, public CrtpFooDouble<Derived>
{
void fooInt()
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void fooDouble()
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};
解决这个问题的另一种创造性方法是使用添加一些重载的能力来区分 foo()
:
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
template<typename T>
struct Tag{};
template<typename T>
struct Overloader : public Foo<T>
{
virtual void foo(Tag<T>) = 0;
void foo() override
{
foo(Tag<T>{});
}
};
struct Derived : public Overloader<int>, public Overloader<double>
{
void foo(Tag<int>) override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void foo(Tag<double>) override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
};