C++ 通过CRTP基类重写虚拟函数

C++ 通过CRTP基类重写虚拟函数,c++,polymorphism,virtual-functions,crtp,C++,Polymorphism,Virtual Functions,Crtp,Old:如何通过CRTP基类重写虚拟函数 struct I { virtual void foo() = 0; }; template<class D> struct B { void foo() { } }; // provides implementation of foo in D struct D : I, B<D> { }; // D has an implementation of foo that should override I int main(

Old:如何通过CRTP基类重写虚拟函数

struct I { virtual void foo() = 0; };

template<class D>
struct B { void foo() { } }; // provides implementation of foo in D

struct D : I, B<D> { }; // D has an implementation of foo that should override I

int main() { D d; }

您不必要地混合了两个不同的概念:crtp和继承虚拟函数的实现

crtp用于编译时多态性,虚拟函数用于运行时多态性

也就是说,您可以通过虚拟继承层次结构中的优势在虚拟函数的实现中进行继承,这大致产生了java/c实现继承的效果


例如:

struct tutti_i
{
    virtual int frutti() const = 0;
};

struct tutti_impl_1
    : virtual tutti_i
{
    int frutti() const override { return 42; }
};

struct base
    : virtual tutti_i
{};

struct derived
    : base
    , tutti_impl_1
{};

#include <iostream>
int main()
{
    tutti_i&& tutti = derived();
    std::cout << tutti.frutti() << std::endl;
}
struct-tutti\u i
{
虚拟整数frutti()常量=0;
};
结构tutti_impl_1
:虚拟图蒂_i
{
int frutti()常量重写{return 42;}
};
结构基
:虚拟图蒂_i
{};
结构派生
:基本
,tutti_impl_1
{};
#包括
int main()
{
tutti_i&&tutti=derived();

std::cout您不必要地混合了两个不同的概念:crtp和继承虚拟函数的实现

crtp用于编译时多态性,虚拟函数用于运行时多态性

也就是说,您可以通过虚拟继承层次结构中的优势在虚拟函数的实现中进行继承,这大致产生了java/c实现继承的效果


例如:

struct tutti_i
{
    virtual int frutti() const = 0;
};

struct tutti_impl_1
    : virtual tutti_i
{
    int frutti() const override { return 42; }
};

struct base
    : virtual tutti_i
{};

struct derived
    : base
    , tutti_impl_1
{};

#include <iostream>
int main()
{
    tutti_i&& tutti = derived();
    std::cout << tutti.frutti() << std::endl;
}
struct-tutti\u i
{
虚拟整数frutti()常量=0;
};
结构tutti_impl_1
:虚拟图蒂_i
{
int frutti()常量重写{return 42;}
};
结构基
:虚拟图蒂_i
{};
结构派生
:基本
,tutti_impl_1
{};
#包括
int main()
{
tutti_i&&tutti=derived();

std::cout您可以将
D::foo()
实现为调用
B::foo()
的普通包装器。如果您有很多地方需要这样做,您可以制作一个宏来提供帮助,如:

#define WRAP(CLASS, METHOD) \
    METHOD() { return CLASS::METHOD(); }

struct D : I, B<D>
{
    void WRAP(B<D>, foo);
};
#定义换行(类、方法)\
方法(){返回类::方法();}
结构D:I,B
{
空心包层(B,foo);
};

您可以将
D::foo()
实现为一个调用
B::foo()
的简单包装器。如果您有很多地方需要这样做,您可以制作一个宏来提供帮助,例如:

#define WRAP(CLASS, METHOD) \
    METHOD() { return CLASS::METHOD(); }

struct D : I, B<D>
{
    void WRAP(B<D>, foo);
};
#定义换行(类、方法)\
方法(){返回类::方法();}
结构D:I,B
{
空心包层(B,foo);
};

除了明显但笨拙的
void foo(){B::foo();}
解决方案之外,您还可以将“实现一个
foo
”接口与更完整的接口
I
分开:

struct FooInterface {
    virtual ~FooInterface() {}
    virtual void foo() = 0;
};

struct I : public virtual FooInterface {};

template<class D>
struct B : public virtual FooInterface { void foo() { } };

struct D : I, B<D> {};

int main() { D d; }
struct接口{
虚拟~FooInterface(){}
虚拟void foo()=0;
};
结构I:公共虚拟接口{};
模板
结构B:公共虚拟foo接口{void foo(){};
结构D:I,B{};
int main(){D;}

除了明显但笨拙的
void foo(){B::foo();}
解决方案之外,您还可以将“实现一个
foo
”接口与更完整的接口
I
分开:

struct FooInterface {
    virtual ~FooInterface() {}
    virtual void foo() = 0;
};

struct I : public virtual FooInterface {};

template<class D>
struct B : public virtual FooInterface { void foo() { } };

struct D : I, B<D> {};

int main() { D d; }
struct接口{
虚拟~FooInterface(){}
虚拟void foo()=0;
};
结构I:公共虚拟接口{};
模板
结构B:公共虚拟foo接口{void foo(){};
结构D:I,B{};
int main(){D;}

对于那些不关心B是否从I继承的人,您也可以按照最初的要求使用CRTP实现这一点:

struct I { virtual void foo() = 0; };

template <class D>
struct B : I { void foo(){ /* Do something fancy with D's type */ } };

struct D : B<D> { };
struct I{virtual void foo()=0;};
模板
结构B:I{void foo(){/*对D的类型*/}做一些有趣的事情;
结构D:B{};
如果您需要进一步的继承,以便foo的实现始终是最派生的类型,您可以引入一个中间类型来消除使用哪个foo实现的歧义:

struct I { virtual void foo() = 0; };

template <class T>
struct B : virtual I { void foo() { /* Do something fancy with the most-derived type */ }};

struct D : B<D> { };

template <typename Base, typename Derived>
struct InheritFrom : public Base, public B<D> { void foo() { B<D>::foo(); } };

struct FurtherDerived : InheritFrom<D, FurtherDerived> { };
struct I{virtual void foo()=0;};
模板
结构B:virtuali{void foo(){/*使用最派生的类型*/}做一些有趣的事情;
结构D:B{};
模板
结构继承自:public Base,public B{void foo(){B::foo();};
结构进一步派生:继承自{};

对于那些不关心B是否从I继承的人,您也可以按照最初的要求使用CRTP实现这一点:

struct I { virtual void foo() = 0; };

template <class D>
struct B : I { void foo(){ /* Do something fancy with D's type */ } };

struct D : B<D> { };
struct I{virtual void foo()=0;};
模板
结构B:I{void foo(){/*对D的类型*/}做一些有趣的事情;
结构D:B{};
如果您需要进一步的继承,以便foo的实现始终是最派生的类型,您可以引入一个中间类型来消除使用哪个foo实现的歧义:

struct I { virtual void foo() = 0; };

template <class T>
struct B : virtual I { void foo() { /* Do something fancy with the most-derived type */ }};

struct D : B<D> { };

template <typename Base, typename Derived>
struct InheritFrom : public Base, public B<D> { void foo() { B<D>::foo(); } };

struct FurtherDerived : InheritFrom<D, FurtherDerived> { };
struct I{virtual void foo()=0;};
模板
结构B:virtuali{void foo(){/*使用最派生的类型*/}做一些有趣的事情;
结构D:B{};
模板
结构继承自:public Base,public B{void foo(){B::foo();};
结构进一步派生:继承自{};

否。A
B
不是一个
I
B
可以实现
I
接口的一部分,但不是全部。某些东西必须从I继承并实现foo。一种可能是让D这样做并转发到B。或者您可以向B添加另一个模板参数,并让B从那里继承。有无数个可能性,只需要一个:某些东西必须从I继承并在那里实现。
D
继承自
I
,并具有
foo
实现(由
B
提供)有一个
foo
实现是不够的?我可以用一个调用
B::foo
的伪函数在
D
中重新实现它,但我不喜欢这个解决方案。不。a
B
不是
I
的接口的一部分,但不是全部。必须有东西继承from I和实现foo。一种可能是让D这样做并转发到B。或者你可以向B添加另一个模板参数,并让B从那里继承。有无数种可能,只需要一种:某些东西必须从I继承并在那里实现。
D
I
继承并具有