c ++:传递可以使用的允许类列表

时间:2015-06-11 10:18:22

标签: c++ inheritance

我有两组课程,比如说集A = {a1, a2, a3}来自AsuperB = {b1, b2}全部来自Bsuper,只有包含A和B的类可以可以一起使用(例如,a1和b2,或a3和b1;它们具有逻辑依赖性)。如何通过适当的课堂设计将此信息传达给用户?

一种方法是让枚举与每个类相关联并将它们呈现在某个地方。例如:

class LogicalGrouping{
enum gr1{A1, A2, A3};
enum gr2{B1, B2};

Asuper *a;
Bsuper *b;

setA(Asuper *a); //user can now manually check the types in gr1 and assign
setB(Bsuper *b);

};

但在我看来,这非常难看。一个人必须手动解码枚举的含义并分配它们。我想要像classlist {a1, a2, a3};这样的类列表。 有更清洁的方法吗?

2 个答案:

答案 0 :(得分:1)

创建两个接口IA和IB让所有A实现IA并且所有B实现IB然后创建继承自IA和IB的第三接口IAB。这将确保您拥有其中一个。

当你的班级用户想要使用你的班级时,他需要从IAB继承,迫使他选择一个A和一个B.

答案 1 :(得分:1)

这花了很长时间,但这是我提出的代码,基于@TartanLlama的建议(或多或少):

#include <iostream>
#include <cassert>
#include <type_traits>
#include <typeinfo>
#include <string>

//--- The class hierarchy
struct A{ virtual std::string name() const{ return "A";} };
struct B{ virtual std::string name() const{ return "B";} };

template <int i> struct An : A
{
  virtual std::string name() const{ return A::name() + std::to_string(i);}
};
template <int i> struct Bn : B
{
  virtual std::string name() const{ return B::name() + std::to_string(i);}
};
template <int i> struct AnBn : An<i>, Bn<i>
{
  virtual std::string name() const{ return An<i>::name() + Bn<i>::name(); }
};
template <int i,int j> struct AnBm : An<i>, Bn<j>
{
  virtual std::string name() const{ return An<i>::name() + Bn<j>::name(); }
};

//--- End of class hierarchy


//--- The magic that determines whether A/B is base of
template <class T> using A_is_base_of = 
    std::is_base_of<A,typename std::remove_reference<T>::type>;
template <class T> using B_is_base_of = 
    std::is_base_of<B,typename std::remove_reference<T>::type>;
template <class T> 
struct AB_is_base_of
{
  const static bool value = A_is_base_of<T>::value && B_is_base_of<T>::value;
  typedef typename std::integral_constant<bool,value>::type type;
};

//--- A tester - requires T has member function name... just for now...
struct IsAB_BaseOf
{
  template <class T>
    static void test(T&& value)
  {
    return test(std::forward<T>(value), 
      typename AB_is_base_of<T>::type());
  }

  private: template <class T>
    static void test(T&& value, std::true_type) 
    {
        std::cout << value.name() << " derives from both A and B" << std::endl;
    }
  private: template <class T>
    static void test(T&& value, std::false_type)
    {
        std::cout << value.name() << " does not derive from both A and B" << std::endl;
    }
};

template <class T> 
bool ab_IsBaseOf( T&& type )
{
  return AB_is_base_of<T>::value;
}

int main() {
  assert(!ab_IsBaseOf(An<0>()));
  assert(!ab_IsBaseOf(Bn<0>()));
  assert(!ab_IsBaseOf(Bn<0>()));
  assert(!ab_IsBaseOf(An<0>()));
  assert(!ab_IsBaseOf(An<0>()));
  assert(!ab_IsBaseOf(Bn<0>()));
  assert(ab_IsBaseOf(AnBn<0>()));
  assert(ab_IsBaseOf(AnBm<0,1>()));

  IsAB_BaseOf::test(AnBm<0,1>());
  IsAB_BaseOf::test(An<0>());
  IsAB_BaseOf::test(Bn<0>());
}

Output:
A0B1 derives from both A and B
A0 does not derive from both A and B
B0 does not derive from both A and B

基本上:

  • 创建一个元函数,确定A和B何时是T的基础。
  • 创建一个函数模板助手来调用元函数
    有条不紊地(ab_IsBaseOf)。
  • 创建继承结构并测试...

这个想法是,如果A和B是T的基础,ab_IsBaseOf返回true。

编辑:

可以毫不费力地从元函数创建一个类型,您可以将其用作函数的参数,只有当T具有正确的类型(称为标签调度)时才会调用该函数。

编辑:

我现在修改了呈现的源代码,使用标签调度根据类型T是否从A和B派生来选择一个函数,根据我的理解,这是OP想要的。欢迎提出问题。