编译时初始化和运行时访问包含派生元素的 initializer_list 向量

compile-time initializing and runtime accessing an initializer_list vector containing derived elements

在下面的代码中,初始化列表用 B 和 C 对象初始化,其 ctors 分别传入值“bbb”和 333。由于这些对象派生自 A,因此列表正确地创建了两个 A 元素。

#include <string>
#include <vector>
#include <iostream>

struct A 
{
  char ch;
};

struct B : A 
{ 
  B( std::string str ) : str( str ) {}
  std::string str;
};

struct C : A 
{ 
  C( int num ) : num( num ) {}
  int num;
};

struct D
{
  D( std::initializer_list< A* > initializerList )
    : variadicVect( initializerList )
  {}

  std::vector< A* > variadicVect;
};

int main()
{
  D d { new B { "bbb" }, new C { 333 } };
  d.variadicVect[ 0 ]->ch = 'm'; // ok, but accesses base member
  //std::cout << d.variadicVect[ 0 ]->str << std::endl; // error C2039: 'str': is not a member of 'A'
  //std::cout << d.variadicVect[ 1 ]->num << std::endl; // error C2039: 'num': is not a member of 'A'

  return 0;
}

@Jarod42 在 link 中报告了类似的问题。他确定对象切片是问题所在。为了避免这种按值赋值的问题,我新建了初始化列表对象,但仍然无法访问派生的 class.

我尝试的另一个尝试是模板化 initializer_list 类型(代码未显示),但我收到此错误:'D::variadicVect':仅允许静态数据成员模板'

我的目标是能够使用在编译时选择派生类型的各种派生对象来初始化列表,并且能够在运行时正确访问它们。这可能吗?

要编译您的代码,您必须将向量元素转换为适当的类型:

std::cout << static_cast<B*>(d.variadicVect[ 0 ])->str << std::endl;
std::cout << static_cast<C*>(d.variadicVect[ 1 ])->num << std::endl;

否则 C++ 将它们视为类型 A,并且只有来自 A 的接口可用。

其他解决方案是向 A 添加虚函数(virtual std::string Str(){return "";}virtual int Num(){return 0;})并在需要时在基础 类 中覆盖它们。那么你就不必施法了。下面的示例:

http://coliru.stacked-crooked.com/a/ed7c73a5d8afa5e9

#include <string>
#include <vector>
#include <iostream>

struct A 
{
  char ch;
  virtual std::string Str() { return ""; }
  virtual int Num() { return 0; }
};

struct B : A 
{ 
  B( std::string str ) : str( str ) {}
  std::string str;
  std::string Str() override { return str; }
};

struct C : A 
{ 
  C( int num ) : num( num ) {}
  int num;
  int Num() override { return num; }
};

struct D
{
  D( std::initializer_list< A* > initializerList )
    : variadicVect( initializerList )
  {}

  std::vector< A* > variadicVect;

};

int main()
{
  D d { new B { "bbb" }, new C { 333 } };
  d.variadicVect[ 0 ]->ch = 'm'; // ok, but accesses base member
  std::cout << d.variadicVect[ 0 ]->Str() << std::endl;
  std::cout << d.variadicVect[ 1 ]->Num() << std::endl;

  return 0;
}

这个问题在我的另一个帖子中得到了巧妙的隐含回答(请参阅其编辑部分,了解我为什么花了这么长时间才弄清楚正确的问题是什么,然后解决方案 - 类似联合类 - 只是让构造函数和析构函数正确的问题):.