如何在类层次结构中找到两个类的共同父类

How to find the common parent of two classes in a class hierarchy

本文关键字:两个 父类 层次结构      更新时间:2023-10-16

我有一个定义如下的单一继承类层次结构:

struct A        { using Parent = void;  void fnct() { std::cout << "An";   } };
struct AA : A   { using Parent = A;     void fnct() { std::cout << "AAn";  } };
struct AB : A   { using Parent = A;     void fnct() { std::cout << "ABn";  } };
struct AAA : AA { using Parent = AA;    void fnct() { std::cout << "AAAn"; } };
struct AAB : AA { using Parent = AA;    void fnct() { std::cout << "AABn"; } };
struct ABA : AB { using Parent = AB;    void fnct() { std::cout << "ABAn"; } };
struct ABB : AB { using Parent = AB;    void fnct() { std::cout << "ABBn"; } };

层次结构中的每个类定义了它的直接父类的别名Parent和成员函数void fnct()

我需要定义一个模板函数call_fnct_upto_parent<P,C>(C&),对于类C的给定对象和类层次结构的给定父类P,调用从对象类型C到父类型P的所有成员函数fnct()。我使用SFINAE实现这一点,如下所示:

template<class P, class C>
typename std::enable_if<!std::is_same<P,C>::value,void>::type call_fnct_upto_parent(C& c)
{
    c.fnct();
    static_assert(!std::is_same<typename C::Parent,void>::value, "parent not found");
    call_fnct_upto_parent<P, typename C::Parent>(c);
}
template<class P, class C>
typename std::enable_if<std::is_same<P,C>::value,void>::type call_fnct_upto_parent(C& c)
{
    c.fnct();
}
只要PC的父节点,上面定义的call_fnct_upto_parent<P,C>(C&)函数就可以正常工作。例如,对call_fnct_upto_parent<A>(aaa)的调用,其中aaa的类型为AAA,会导致后续对aaa.AAA::fnct()aaa.AA::fnct()aaa.A::fnct()的调用,这些调用在编译时解析。

现在,我想定义一个模板函数call_fnct_upto_common_parent<Ch,Co>(Co&),对于类Co的给定对象和类层次结构的给定类Ch,调用从对象类型Co到类ChCo最接近的共同父类的类型P的所有成员函数fnct()。例如,对call_fnct_upto_common_parent<AB>(aaa)的调用将导致对aaa.AAA::fnct(), aaa.AA::fnct()aaa.A::fnct()的后续调用,因为A类是ABAAA类最接近的共同父类。

这样的函数可以实现吗?如何实现?如果可行,最好使用在编译时解析调用的解决方案。

您可以使用std::is_base_of与您现有的代码具有类似的结构:

template<class T, class U>
typename std::enable_if<!std::is_base_of<U,T>::value,void>::type 
call_fnct_upto_common_parent(U& u)
{
    u.fnct();
    static_assert(!std::is_same<typename U::Parent,void>::value, "parent not found");
    call_fnct_upto_common_parent<T, typename U::Parent>(u);
}
template<class T, class U>
typename std::enable_if<std::is_base_of<U,T>::value,void>::type 
call_fnct_upto_common_parent(U& u)
{
    u.fnct();
}