具有可以是两种类型之一的数据成员的类

Posted

技术标签:

【中文标题】具有可以是两种类型之一的数据成员的类【英文标题】:Class with data member that can be one of two types 【发布时间】:2020-03-31 17:58:44 【问题描述】:

最好用一些代码来解释:

class MyClass 
  public:
    MyClass(const std::string& d1, const std::string& d2, const std::vector<AorB>& d3) : data1(d1), data2(d2), data3(d3) 

    std::string getData1();
    std::string getData2();
    std::vector<AorB> getData3();

  private:
    std::string data1;
    std::string data2;
    std::vector<AorB> data3;


int main() 
  MyClass myClassA("d1", "d2", std::vector<A>());
  MyClass myClassB("d1", "d2", std::vector<B>());

  A myA = myClassA.getData3();
  B myB = myClassB.getData3();

当使用 boost 变体或 boost any 时,此工作流“几乎”有效,但我要避免的是调用 boost::get 以获取实际类型的 getData3 结果。换句话说,我不希望 MyClass 的使用者必须知道 A 或 B 是否存储在 data3 中。我只是希望他们能够调用 getData3(),它是在创建时传递的任何类型。

我认为可以通过具有模板专业化/递归继承的模板来实现,但我不太清楚如何让它发挥作用。也许它看起来像这样?

class MyClass 
  public:
    template <typename AorB>
    MyClass(const std::string& d1, const std::string& d2, const std::vector<AorB>& d3) : data1(d1), data2(d2), data3(d3) 

    std::string getData1();
    std::string getData2();

    template <typename AorB>
    std::vector<AorB> getData3();

  private:
    std::string data1;
    std::string data2;

    template <typename AorB>
    std::vector<AorB> data3;
  

  int main() 
    MyClass myClassA<A>("d1", "d2", std::vector<A>());
    MyClass myClassB<B>("d1", "d2", std::vector<B>());

    A myA = myClassA.getData3();
    B myB = myClassB.getData3();
  

但是这行不通,因为我们不能有非静态模板类成员。

【问题讨论】:

您是要复制std::vector&lt;std::variant&lt;A, B&gt;&gt; 还是std::variant&lt;std::vector&lt;A&gt;, std::vector&lt;B&gt;&gt; AB 是否继承自一个共同的基础?如果不是,我真的不明白“我不希望 MyClass 的消费者必须知道 A 或 B 是否存储在 data3 中”,因为一旦他们调用 getData3,用户就知道它是什么类型 【参考方案1】:

要执行您正在尝试的操作,您需要将模板作为一个整体应用于MyClass,例如:

template <typename AorB>
class MyClass 
  public:
    MyClass(const std::string& d1, const std::string& d2, const std::vector<AorB>& d3) : data1(d1), data2(d2), data3(d3) 

    std::string getData1();
    std::string getData2();
    std::vector<AorB> getData3();

  private:
    std::string data1;
    std::string data2;
    std::vector<AorB> data3;
;

int main() 
  MyClass<A> myClassA("d1", "d2", std::vector<A>());
  MyClass<B> myClassB("d1", "d2", std::vector<B>());

  A myA = myClassA.getData3();
  B myB = myClassB.getData3();

【讨论】:

哎呀,这是一个微不足道的修复,现在感觉有点愚蠢。是的,这正是我想要的,谢谢!【参考方案2】:

您可以在此处使用 union 来设置创建时想要的任何数据类型以及检索时获得的数据类型。 Union 为其所有成员分配一个公共内存位置。联合占用的内存将大到足以容纳联合的最大成员。

union AorB
   
         A;
         B;
   ;

然后在上面的程序中使用

【讨论】:

使用union 将不允许从AB 返回getData3,除非您建议返回联合,这让调用者知道哪个是活动的会员 在这种情况下,使用union 比使用variant 没有任何好处

以上是关于具有可以是两种类型之一的数据成员的类的主要内容,如果未能解决你的问题,请参考以下文章

boost::variant:递归向量类型的奇怪行为

类的静态成员是不是可以与 C++ 中它所属的类具有相同的类型

具有所有私有成员的类可以是 POD 类吗?

两种类型的变量

使用 protobuf-net 序列化具有接口类型成员的类

具有引用数据成员的类的默认构造函数?